1. Read in the data

Load the required packages

[1] "Seurat is loaded correctly"
[1] "viridis is loaded correctly"
[1] "ggpubr is loaded correctly"
[1] "cowplot is loaded correctly"
[1] "ggplot2bdc is loaded correctly"
[1] "patchwork is loaded correctly"

Import GTF file

This will be helpful later on. This contains annotations for each gene:

##Import gtf file:
gtf <- read.table("/Users/Andy/GCSKO/GCSKO_analysis_git/data/Reference/Pberghei.gtf", sep="\t", header = FALSE)

## inspect
head(gtf)

*N.B.This was the .gtf file used for feature counting the data

Import Counts and Pheno files

## read in counts
counts <- read.delim("/Users/Andy/GCSKO/GCSKO_analysis_git/data/Smartseq2/counts_2020.csv", sep = ",", stringsAsFactors = FALSE, row.names = 1)

## read in pheno
pheno <- read.delim("/Users/Andy/GCSKO/GCSKO_analysis_git/data/Smartseq2/pheno_2020.csv", sep = ",", stringsAsFactors = FALSE)

## check dimensions of both
expected_number_of_cells <- ( 384 * 12)
paste("The expected number of cells is", expected_number_of_cells)
[1] "The expected number of cells is 4608"
paste("number of genes in counts", dim(counts)[1], "number of cells in counts", dim(counts)[2])
[1] "number of genes in counts 5250 number of cells in counts 4608"
paste("number of columns in counts", dim(pheno)[2], "number of cells in pheno", dim(pheno)[1])
[1] "number of columns in counts 98 number of cells in pheno 4608"
## make rownames the sample_id in pheno
rownames(pheno) <- pheno$sample_id

## check that the names are the same
paste("Are the names the same?")
[1] "Are the names the same?"
table((colnames(counts) %in% rownames(pheno)))

TRUE 
4608 

Remove Anopheles cells

These cells were included in one of the sequencing runs and are irrelevant.

## get rid of the cells by finding all the cells that have As in their species col
names_of_mosquito_cells <- rownames(pheno[(pheno$species == "As"), ])

## which gives
table(colnames(counts) %in% names_of_mosquito_cells)

FALSE  TRUE 
 4512    96 
## subset 
counts <- counts[,-which(colnames(counts) %in% names_of_mosquito_cells)]
pheno <- pheno[-(which(rownames(pheno) %in% names_of_mosquito_cells)), ]

## check dimensions
paste("number of genes in counts", dim(counts)[1], "number of cells in counts", dim(counts)[2])
[1] "number of genes in counts 5250 number of cells in counts 4512"
paste("number of columns in counts", dim(pheno)[2], "number of cells in pheno", dim(pheno)[1])
[1] "number of columns in counts 98 number of cells in pheno 4512"

Remove control cells:

## find all cells that are labelled as such
names_of_control_cells <- rownames(pheno[(pheno$is_control == "TRUE"), ])

## which gives
table(colnames(counts) %in% names_of_control_cells)

FALSE  TRUE 
 4386   126 
## subset 
counts <- counts[,-which(colnames(counts) %in% names_of_control_cells)]
pheno <- pheno[-(which(rownames(pheno) %in% names_of_control_cells)), ]

## check dimensions
paste("number of genes in counts", dim(counts)[1], "number of cells in counts", dim(counts)[2])
[1] "number of genes in counts 5250 number of cells in counts 4386"
paste("number of columns in counts", dim(pheno)[2], "number of cells in pheno", dim(pheno)[1])
[1] "number of columns in counts 98 number of cells in pheno 4386"

Remove 10 and 27

10 and 27 failed genotyping and so will be removed

## find all cells that are labelled as such
names_of_genotype_fail_cells <- rownames(pheno[(pheno$sub_identity_updated %in% c("GCSKO-10", "WT-10", "GCSKO-27")), ])

## which gives
table(colnames(counts) %in% names_of_genotype_fail_cells)

FALSE  TRUE 
 3732   654 
## subset 
counts <- counts[,-which(colnames(counts) %in% names_of_genotype_fail_cells)]
pheno <- pheno[-(which(rownames(pheno) %in% names_of_genotype_fail_cells)), ]

## check dimensions
paste("number of genes in counts", dim(counts)[1], "number of cells in counts", dim(counts)[2])
[1] "number of genes in counts 5250 number of cells in counts 3732"
paste("number of columns in counts", dim(pheno)[2], "number of cells in pheno", dim(pheno)[1])
[1] "number of columns in counts 98 number of cells in pheno 3732"

Filter non-genes out of counts

Filter out the QC columns contained in counts that do not correspond to genes

## since the datatable currently contains:
paste("The current counts table contains these non-gene rows:")
[1] "The current counts table contains these non-gene rows:"
rownames(counts[-(grep("PBANKA*", rownames(counts))), ])
[1] "__alignment_not_unique" "__ambiguous"            "__no_feature"          
[4] "__not_aligned"          "__too_low_aQual"       
## subset
# make a copy of counts just in case that info is useful in future analysis
counts_genes <- counts
# remove non-gene rows
counts <- counts[(grep("PBANKA*", rownames(counts))), ]
#check
paste("number of genes in counts", dim(counts)[1], "number of cells in counts", dim(counts)[2])
[1] "number of genes in counts 5245 number of cells in counts 3732"

This 5245 includes all types of genes:

## check size
paste("The dimensions of the GTF file are:")
[1] "The dimensions of the GTF file are:"
dim(gtf[-which(gtf$V3 == "CDS"),])
[1] 5245    9
## look at possible types of genes
paste("The types of genes in the dataframe are:")
[1] "The types of genes in the dataframe are:"
names(table(gtf$V3))
[1] "CDS"                    "mRNA"                   "ncRNA"                 
[4] "pseudogenic_transcript" "rRNA"                   "snoRNA"                
[7] "snRNA"                  "tRNA"                  

2. Filtering

set-up data

make seurat object

## make seurat object
ss2_mutants <- CreateSeuratObject(counts = counts, project = "GCSKO", min.cells = 0, min.features = 1, meta.data = pheno)
Feature names cannot have underscores ('_'), replacing with dashes ('-')
## n.b. cells must have at least 1 gene per cell because otherwise this causes problems downstream

## add experiment column to meta data:
ss2_mutants@meta.data$experiment <- "ss2_mutants"

## inspect object
ss2_mutants
An object of class Seurat 
5245 features across 3705 samples within 1 assay 
Active assay: RNA (5245 features, 0 variable features)
## how many genes are not detected at all?
paste(length(which(rowSums(as.matrix(ss2_mutants@assays$RNA@counts)) == 0)), "genes are not detected in any cell")
[1] "63 genes are not detected in any cell"
[1] "27 cells have zero counts"

Filtered Cells Plate Heatmap

set up data

## make dataframe
df_platemap <- data.frame(well_name = pheno$well_name_R, cell_name = rownames(pheno), row.names = rownames(pheno))

## get cells that are filtered out
cells_kept <- which(rownames(df_platemap) %in% rownames(ss2_mutants@meta.data))

## make extra column in plotting df
df_platemap$colour <- "filtered_out"
df_platemap$colour[cells_kept] <- "passed_QC"

## inspect
#head(df_platemap)

##Make a table for each

##make a new dataframe for plotting
table_platemap <- as.data.frame(table(df_platemap$well_name, df_platemap$colour))

## modify names of dataframe
names(table_platemap) <- c("well", "filtered", "frequency")

#make separate dfs
df_1 <- table_platemap[table_platemap$filtered == "filtered_out",]
df_2 <- table_platemap[table_platemap$filtered == "passed_QC",]

# merge them back together
table_platemap <- merge(df_1, df_2, by = "well", all = TRUE)

## remove the irrelevant rows and rename cols and rename rows
table_platemap <- table_platemap[ ,c(1,3,5)]
names(table_platemap) <- c("well", "filtered_out", "passed_QC")
table_platemap$well_name <- rownames(table_platemap)

## add A1?
#table_platemap[96,] <- c("A1", "0", "0")

## add cols for plotting
table_platemap$Row <- as.numeric(match(toupper(substr(table_platemap$well, 1, 1)), LETTERS))
table_platemap$Column <- as.numeric(substr(table_platemap$well, 2, 5))

## calculate a percentage
table_platemap$filtered_pc <- ((table_platemap$filtered_out)/(table_platemap$filtered_out + table_platemap$passed_QC))*100

## due to an error in the scale_y_reverse, you need to make a column of 'reversed' row values to plot
for(i in seq(1,8)){
  table_platemap$Row_rev[table_platemap$Row == i] <- seq(8,1)[i]
}

## find wells where it's zero
zero_wells <- table_platemap$filtered_pc == 0
table_platemap$filtered_pc[zero_wells] <- NA

Plot

## plot
sample_map_no_reads <- ggplot(data=table_platemap, aes(x=Column, y=Row_rev)) +
  #set up the platemap layout
    geom_point(data=expand.grid(seq(1,12), seq(1,8)), aes(x=Var1, y=Var2), color="grey90", fill="white", shape=21, size=8) +
  #Change the shape and colour of points for a variable
    geom_point(aes(colour = filtered_pc), size = 7) +
  #change the colours
    scale_colour_viridis_c(guide = "colourbar", na.value="white") +
  #fix the ratio of coordinates
    coord_fixed(ratio=(13/12)/(9/8), xlim=c(0.5, 12.5), ylim=c(0.6, 8.4)) +
  # make into a plate plot
    theme_bdc_microtiter() +
  #add labels for the y axis
    scale_y_continuous(breaks = seq(1, 8), labels = LETTERS[8:1]) +
  #add labels for the x axis
    scale_x_continuous(position = "top", breaks=seq(1, 12)) +
  #Add a title and change label of fill
    labs(title="The position of cells with zero counts" , size = 6, colour = "percentage of cells in this well with zero counts") +
  #Improve aes of guides
    guides(colour = guide_colorbar(barwidth = 4, barheight = 1, title="percentage of cells in this well with zero counts")) +
# display legend on bottom and make text bigger
    theme(legend.position="bottom", legend.text=element_text(size=10), legend.title = element_text(size = 10))

## print
sample_map_no_reads

## save
ggsave("/Users/Andy/GCSKO/GCSKO_analysis_git/images_to_export/QC_SS2_platemap_no_count.png", plot = sample_map_no_reads, device = "png", path = NULL, scale = 1, width = 12, height = 12, units = "cm", dpi = 300, limitsize = TRUE)

Filter Mitochondrial

Mitochondrial cell counts

## old method
## This old method just picked out rRNA genes as a rough estimate, the method below picks out all genes expressed from the mitchondrial genome

## extract mitochondrial genes 
#mito_genes <- gtf[which(gtf$V3 == "rRNA"),]$V9
#mito_genes <- gsub(";.*","", gsub("gene_id ", "", mito_genes))
#paste("These are the mitochondrial genes")
#head(mito_genes)

## make a percentage mitocondrial for each cell (this will work as long as you filter cells out with zero counts)
#ss2_mutants <- PercentageFeatureSet(ss2_mutants, features = which(rownames(counts) %in% mito_genes), col.name = "percent.mt")
## extract mito genes
mito_genes <- ss2_mutants@assays$RNA@counts@Dimnames[[1]][grep("^PBANKA-MIT",ss2_mutants@assays$RNA@counts@Dimnames[[1]])]

## plot the genes individually
VlnPlot(object = ss2_mutants, features = mito_genes, pt.size = 0.01, group.by = "experiment")
All cells have the same value of PBANKA-MIT00100:rRNA.All cells have the same value of PBANKA-MIT00200:rRNA.All cells have the same value of PBANKA-MIT00900:rRNA.All cells have the same value of PBANKA-MIT02000:rRNA.All cells have the same value of PBANKA-MIT02600:rRNA.All cells have the same value of PBANKA-MIT03000:rRNA.All cells have the same value of PBANKA-MIT03300:rRNA.All cells have the same value of PBANKA-MIT03400:rRNA.

## make a percentage mitocondrial for each cell (this will work as long as you filter cells out with zero counts)
ss2_mutants <- PercentageFeatureSet(ss2_mutants, pattern = "^PBANKA-MIT", col.name = "percent.mt")

plot percentage mitochondrial

## plot for percentage of mitochondrial reads
v1 <- VlnPlot(object = ss2_mutants, features = "percent.mt", group.by = "sub_identity_updated", pt.size = 0.01) + 
  ## add a line where we will filter 
  geom_hline(yintercept=20) +
  ## remove legend
  theme(legend.position = "none") +
  ## change labels
  labs(x = "Genotype", y = "% Mitochondrial Reads") +
  ## remove plot title
  theme(plot.title = element_blank())

## plot for percentage of mitochondrial reads
v2 <- VlnPlot(object = ss2_mutants, features = "percent.mt", group.by = "experiment", pt.size = 0.01) +
  geom_hline(yintercept=20) +
  ## remove legend
  theme(legend.position = "none") +
  ## fremove axis labels
  labs(x="", y = "") +
  ## remove axis elements
  theme(plot.title = element_blank(), axis.text.y = element_blank(),
        axis.ticks.y = element_blank()) +
  ## change label on bottom of plot
  scale_x_discrete(labels = "All cells")

## plot together
QC_mito_violin <- v1 + v2 + plot_layout(ncol = 2, nrow = 1, widths = c(4, 1), heights = c(2, 2))

## print
QC_mito_violin

## save
ggsave("/Users/Andy/GCSKO/GCSKO_analysis_git/images_to_export/QC_SS2_mito_violin.png", plot = QC_mito_violin, device = "png", path = NULL, scale = 1, width = 15, height = 10, units = "cm", dpi = 300, limitsize = TRUE)

make a dataframe for plotting

df <- data.frame(nCount = log10(ss2_mutants@meta.data$nCount_RNA), nGenes = ss2_mutants@meta.data$nFeature_RNA, identity = ss2_mutants@meta.data$identity_updated, identity_gene = ss2_mutants@meta.data$identity_gene_updated, percent_mt = ss2_mutants@meta.data$percent.mt)

Where do mitchondrial poor cells lie?

## make extra col for filtered values:
filtered_out_cells <- which(df$percent_mt > 20) 

## plot
QC_mito_graph <- ggplot(df, aes(x = nCount, y = nGenes)) + 
  geom_point(alpha = 0.4) +
  scale_size(range = c(0.1,4)) +
  #geom_rug() + 
  scale_y_continuous(name = "Number of Detected Genes") + 
  scale_x_continuous(name = "log10(Number of Total Counts)") +
  scale_color_viridis(option = "D") +
  theme_pubr() +
  theme(legend.position = "bottom") +
  geom_vline(xintercept=3) +
  geom_hline(yintercept=220) +
  geom_hline(yintercept=3300) +
  #annotate selected points
  annotate("point", df$nCount[filtered_out_cells], df$nGenes[filtered_out_cells], size = 2, colour = "orange")

## add this to gemo_point if needed: aes(colour = percent_mt, size = percent_mt)

## print
QC_mito_graph

## save
ggsave("/Users/Andy/GCSKO/GCSKO_analysis_git/images_to_export/QC_SS2_mito_graph.png", plot = QC_mito_graph, device = "png", path = NULL, scale = 1, width = 10, height = 10, units = "cm", dpi = 300, limitsize = TRUE)

[1] "The nGene and nCounts filters catch most of the high % mito cells ( 115 ) but introducing a filter would capture a further 68"
## plot 1
plot1 <- FeatureScatter(ss2_mutants, feature1 = "nCount_RNA", feature2 = "percent.mt", pt.size = 0.01, group.by = "identity_updated")

## plot 2
plot2 <- FeatureScatter(ss2_mutants, feature1 = "nCount_RNA", feature2 = "nFeature_RNA", pt.size = 0.01, group.by = "identity_updated")

## plot together
plot1 + plot2

Filter poor quality cells

in the MCA paper: “Cells with fewer than 1000 genes per cell and 2500 reads per cell were removed from the liver-stage parasites, trophozoites, male and female gametocytes, ookinetes, ookinetes/oocysts, and oocyst stages. Cells with fewer than 500 genes per cell and 2500 reads per cell were removed from schizonts and injected sporozoites. Cells with fewer than 40 genes per cell and 1000 reads per cell were removed from merozoites, rings, and gland sporozoites (fig. S2 and table S1). Additionally, we removed genes from further analysis that were detected in fewer than two cells across the entire dataset. The final dataset contained 1787 high-quality single cells from 1982 sequenced cells and 5156 genes out of 5245 genes with annotated transcripts.”

so use: 1000 reads per cell & 40 genes per cell as absolute minimums

## plot main dotplot
plot1 <- ggplot(df, aes(x = nCount, y = nGenes, color = identity)) + 
  geom_point(aes(color = identity), size = 0.1) +
  geom_rug() + 
  scale_y_continuous(name = "Number of Detected Genes") + 
  scale_x_continuous(name = "log10(Number of Total Counts)") + 
  theme_pubr() +
  theme(legend.position = "bottom") +
  geom_vline(xintercept=3) +
  geom_hline(yintercept=220) +
  geom_hline(yintercept=3300) +
  ## improve aesthetics of guide
  guides(colour = guide_legend(override.aes = list(size=4)), title="Genotype")

## plot density plot x
dens1 <- ggplot(df, aes(x = nCount, fill = identity)) + 
  geom_density(alpha = 0.2) + 
  theme_void() + 
  theme(legend.position = "none")

## plot density plot y
dens2 <- ggplot(df, aes(x = nGenes, fill = identity)) + 
  geom_density(alpha = 0.2) + 
  theme_void() + 
  theme(legend.position = "none") + 
  coord_flip()

## plot together
QC_composite_plot <- dens1 + plot_spacer() + plot1 + dens2 + plot_layout(ncol = 2, nrow = 2, widths = c(4, 1), heights = c(1, 4))

## print
QC_composite_plot


## save
ggsave("/Users/Andy/GCSKO/GCSKO_analysis_git/images_to_export/QC_SS2_composite_plot.png", plot = QC_composite_plot, device = "png", path = NULL, scale = 1, width = 20, height = 20, units = "cm", dpi = 300, limitsize = TRUE)

3. Analysis

Final filter

filter out cells

## subset
ss2_mutants_final <- subset(ss2_mutants, subset = nFeature_RNA > 220 & nFeature_RNA < 3300 & percent.mt < 20 & nCount_RNA > 1000)

## inspect resultant object
ss2_mutants_final
An object of class Seurat 
5245 features across 2970 samples within 1 assay 
Active assay: RNA (5245 features, 0 variable features)
[1] "735  cells are removed by these filters"

Platemap heatmap for failed cells

set up data

## make dataframe
df_platemap <- data.frame(well_name = pheno$well_name_R, cell_name = rownames(pheno), row.names = rownames(pheno))

## get cells that are filtered out
cells_kept <- which(rownames(df_platemap) %in% rownames(ss2_mutants_final@meta.data))

## make extra column in plotting df
df_platemap$colour <- "filtered_out"
df_platemap$colour[cells_kept] <- "passed_QC"

## inspect
head(df_platemap)

## make a new dataframe with metrics of interest
table_platemap <- as.data.frame(table(df_platemap$well_name, df_platemap$colour))
names(table_platemap) <- c("well", "filtered", "frequency")

# make separate dfs
df_1 <- table_platemap[table_platemap$filtered == "filtered_out",]
df_2 <- table_platemap[table_platemap$filtered == "passed_QC",]

# merge them back together
table_platemap <- merge(df_1, df_2, by = "well", all = TRUE)

## remove the irrelevant rows and rename cols and rename rows
table_platemap <- table_platemap[ ,c(1,3,5)]
names(table_platemap) <- c("well", "filtered_out", "passed_QC")
table_platemap$well_name <- rownames(table_platemap)

## add cols for plotting
table_platemap$Row <- as.numeric(match(toupper(substr(table_platemap$well, 1, 1)), LETTERS))
table_platemap$Column <- as.numeric(substr(table_platemap$well, 2, 5))

## inspect:
head(table_platemap)

## calculate percentage
table_platemap$filtered_pc <- ((table_platemap$filtered_out)/(table_platemap$filtered_out + table_platemap$passed_QC))*100

## due to an error in the scale_y_reverse, you need to make a column of 'reversed' row values to plot
for(i in seq(1,8)){
  table_platemap$Row_rev[table_platemap$Row == i] <- seq(8,1)[i]
}

zero_wells <- table_platemap$filtered_pc == 0
table_platemap$filtered_pc[zero_wells] <- NA

plot

## plot
platemap_failed_qc <- ggplot(data=table_platemap, aes(x=Column, y=Row_rev)) +
  #set up the platemap layout
    geom_point(data=expand.grid(seq(1,12), seq(1,8)), aes(x=Var1, y=Var2), color="grey90", fill="white", shape=21, size=8) +
  #Change the shape and colour of points for a variable
    geom_point(aes(colour = filtered_pc), size = 7) +
  #change the colours
    scale_colour_viridis_c(guide = "colourbar", na.value="white") +
  #Add a title and change label of fill
    labs(title="The position of cells that failed QC", size = 6) +
  #fix the ratio of coordinates
    coord_fixed(ratio=(13/12)/(9/8), xlim=c(0.5, 12.5), ylim=c(0.6, 8.4)) +
  # make into a plate plot
    theme_bdc_microtiter() +
  #add labels for the y axis
    scale_y_continuous(breaks = seq(1, 8), labels = LETTERS[8:1]) +
  #add labels for the x axis
    scale_x_continuous(position = "top", breaks=seq(1, 12)) +
  #Improve aes of guides
    guides(colour = guide_colorbar(barwidth = 4, barheight = 1, title="percentage of cells in well that failed QC")) +
  # display legend on bottom and make text bigger
    theme(legend.position="bottom", legend.text=element_text(size=10), legend.title = element_text(size = 9))

## print
platemap_failed_qc

## save
ggsave("/Users/Andy/GCSKO/GCSKO_analysis_git/images_to_export/QC_SS2_platemap_failed.png", plot = platemap_failed_qc, device = "png", path = NULL, scale = 1, width = 10, height = 10, units = "cm", dpi = 300, limitsize = TRUE)

bar chart of distance from edge of plate

Make a bar graph that describes the number of failed cells by distance from the edge of the plate

## get lists of cells for each square around the plate
total_0 <- table_platemap[which(table_platemap$Row %in% c(1,8) | table_platemap$Column %in% c(1,12)), ]

total_1 <- table_platemap[which(table_platemap$Row %in% c(2,7) | table_platemap$Column %in% c(2,11)), ]
total_1 <- total_1[-which(total_1$well %in% total_0$well),]

total_2 <- table_platemap[which(table_platemap$Row %in% c(3,6) | table_platemap$Column %in% c(3,10)), ]
total_2 <- total_2[-which(total_2$well %in% total_0$well | total_2$well %in% total_1$well),]

total_3 <- table_platemap[which(table_platemap$Row %in% c(4,5) | table_platemap$Column %in% c(4,9)), ]
total_3 <- total_3[-which(total_3$well %in% total_0$well | total_3$well %in% total_1$well | total_3$well %in% total_2$well),]

## create a dataframe which calculates the percentage failed for each distance from the edge
frequency_of_failed_cells <- data.frame(percentage_failed = 
                                          c(
                                            sum(total_0$filtered_out) / (sum(total_0$passed_QC) + sum(total_0$filtered_out)),
                                            sum(total_1$filtered_out) / (sum(total_1$passed_QC) + sum(total_1$filtered_out)),
                                            sum(total_2$filtered_out) / (sum(total_2$passed_QC) + sum(total_2$filtered_out)),
                                            sum(total_3$filtered_out) / (sum(total_3$passed_QC) + sum(total_3$filtered_out))
                                          ))

## neaten the dataframe
frequency_of_failed_cells$distance_from_edge <- c(0,1,2,3)
position_qc_fail <- ggplot(frequency_of_failed_cells, aes(x=distance_from_edge, y=percentage_failed)) +
  geom_bar(stat="identity", fill="black")+
  theme_classic() +
  theme(panel.grid.major.x = element_blank(), panel.grid.minor.x = element_blank(), text = element_text(size=12)) +
  ## change the axis titles
  labs(y= "Cells that failed QC (%)", x = "Number of wells from the edge of the plate") +
  ## prevent the title going off the edge of the plot
  coord_cartesian(clip = 'off')

## save
ggsave("/Users/Andy/GCSKO/GCSKO_analysis_git/images_to_export/QC_SS2_failed_position.png", plot = position_qc_fail, device = "png", path = NULL, scale = 1, width = 10, height = 10, units = "cm", dpi = 300, limitsize = TRUE)

## plot
position_qc_fail

Mapping Plot (Figure S6A)

prepare

## make dataframe
df_mapping_rates_hisat <- data.frame(alignment_rate = pheno$overall_hisat2_alignment_rate, cell_name = rownames(pheno), row.names = rownames(pheno))

## get cells that are filtered out
cells_filtered <- which(rownames(df_mapping_rates_hisat) %in% rownames(ss2_mutants_final@meta.data))

## make extra column in plotting df
df_mapping_rates_hisat$colour <- "Failed QC"
df_mapping_rates_hisat$colour[cells_filtered] <- "Passed QC"

## plot
mapping_rate_plot <- ggplot(df_mapping_rates_hisat, aes(x = reorder(cell_name,alignment_rate,sum), y=alignment_rate, fill = colour)) +
  geom_col() + 
  theme(legend.position = "none") +
  labs(x="Cells", y = "Overall Alignment Rate (%)", size = 15, fill = "QC Result") +
  theme_classic() +
  theme(plot.title = element_blank(), axis.text.x = element_blank(),
        axis.ticks.x = element_blank(), text = element_text(size=20)) +
  ## change the colours
   scale_fill_manual(values=c("red2", "green4"))

## save
ggsave("/Users/Andy/GCSKO/GCSKO_analysis_git/images_to_export/QC_SS2_mapping_rate.eps", plot = mapping_rate_plot, device = "eps", path = NULL, scale = 1, width = 20, height = 10, units = "cm", dpi = 300, limitsize = TRUE)

## plot
mapping_rate_plot

Recovery plots

How many cells are recovered per condition?

## extract data
df_cells_recovered <- as.data.frame(table(ss2_mutants_final@meta.data$sub_identity_updated))
df_cells_profiled <- as.data.frame(table(pheno$sub_identity_updated))

## make a df of the metrics
df_cells_recovered <- merge(df_cells_recovered, df_cells_profiled, by = "Var1")
names(df_cells_recovered) <- c("genotype", "recovered", "profiled")

## calculate perecentage
df_cells_recovered$recovered_pc <- (df_cells_recovered$recovered/df_cells_recovered$profiled)*100

## round up percentage for labels
df_cells_recovered$recovered_pc_rounded <- signif(df_cells_recovered$recovered_pc, 2)
df_cells_recovered$recovered_pc_rounded <- paste0(df_cells_recovered$recovered_pc_rounded, " %")

## make a column for number of cells annotation
df_cells_recovered$number_cells_annotation <- paste0("n = ", df_cells_recovered$recovered)

## inspect dataframe
df_cells_recovered
##plot
QC_by_genotype <- ggplot(df_cells_recovered, aes(x=genotype, y=recovered_pc ,fill=genotype)) + 
  geom_bar(stat = "identity") +
  ylim(0, 100) +
  #scale_fill_brewer(palette = "Set1") +
  geom_text(aes(label=recovered_pc_rounded, vjust=0.5, hjust = 1.5)) +
  geom_text(aes(label=number_cells_annotation, vjust=0.5, hjust = -0.05)) +
  labs(y = "Percentage of cells recovered", x = "Genotype") +
  coord_flip(clip = "off") +
  theme_classic() +
  ## remove legend + add border so it doesn't clip the annotation 
  theme(legend.position="none", plot.margin = unit(c(1,3,1,3), "lines"))

## plot
QC_by_genotype

## save
ggsave("/Users/Andy/GCSKO/GCSKO_analysis_git/images_to_export/QC_SS2_by_genotype.png", plot = QC_by_genotype, device = "png", path = NULL, scale = 1, width = 15, height = 10, units = "cm", dpi = 300, limitsize = TRUE)

Investigate 20 and 2 further

## how many plates?
plate_investigation <- pheno[which(pheno$sub_identity_updated == "GCSKO-20" | pheno$sub_identity_updated == "GCSKO-2" | pheno$sub_identity_updated == "WT-2" | pheno$sub_identity_updated == "WT-20"), ]
table(plate_investigation$plate_id_unique)

GCSKO-10_plate_1 GCSKO-10_plate_2 GCSKO-10_plate_3 GCSKO-10_plate_4 
              93               93               93               93 
 GCSKO-2_plate_1  GCSKO-2_plate_2 
              92               92 

add columns if it failed QC:

## get cells that are filtered out
cells_kept <- which(rownames(plate_investigation) %in% rownames(ss2_mutants_final@meta.data))

## make extra column in plotting df
plate_investigation$colour <- "filtered_out"
plate_investigation$colour[cells_kept] <- "passed_QC"

table(plate_investigation$colour)

filtered_out    passed_QC 
         359          197 
## add cols for plotting
plate_investigation$Row <- as.numeric(match(toupper(substr(plate_investigation$well_name_R, 1, 1)), LETTERS))
plate_investigation$Column <- as.numeric(substr(plate_investigation$well_name_R, 2, 5))

plot

## find unique plate names
plate_names <- unique(plate_investigation$plate_id_unique)

## due to an error in the scale_y_reverse, you need to make a column of 'reversed' row values to plot
for(i in seq(1,8)){
  plate_investigation$Row_rev[plate_investigation$Row == i] <- seq(8,1)[i]
}

## make an empty list
plot_list = list()

## run for loop which will generate plots for each plate
for(i in seq_along(plate_names)){
## make df
  table_platemap <- plate_investigation[plate_investigation$plate_id_unique == plate_names[i], ]
  ## plot
  p <- ggplot(data=table_platemap, aes(x=Column, y=Row_rev)) +
  #set up the platemap layout
      geom_point(data=expand.grid(seq(1, 12), seq(1, 8)), aes(x=Var1, y=Var2), color="grey90", fill="white", shape=21, size=8) +
  #Change the shape and colour of points for a variable
    geom_point(aes(colour = colour), size = 7) +
  #change the colours
    #scale_colour_viridis_c(guide = "colourbar", na.value="white") +
  # make into a plate plot
    theme_bdc_microtiter() +
  #fix the ratio of coordinates
    coord_fixed(ratio=(13/12)/(9/8), xlim=c(0.5, 12.5), ylim=c(0.6, 8.4)) +
  #add labels for the y axis
    scale_y_continuous(breaks=seq(1, 8), labels=LETTERS[8:1]) +
  #add labels for the x axis
    scale_x_continuous(position = "top", breaks=seq(1, 12)) +
  #Add a title
    labs(title=plate_names[i] , size = 6, colour = "QC Result") +
  #rotate legend guide because otherwise you can't see numbers:
    guides(fill = guide_colorbar(barwidth = 0.5, barheight = 10, title="Value"), colour = guide_legend(override.aes = list(size=4))) +
  #change the colours
   scale_colour_manual(values=c("red2", "green4")) +
  # make mimnimum point size bigger
    #scale_size_continuous(range = c(2,10)) +
  # make the font size in the legend bigger
    theme(legend.position="bottom", legend.text=element_text(size=10, colour = "black"), legend.title=element_text(size=10))
  
## print
plot_list[[i]] <- p
}

for (i in seq_along(plate_names)) {
    print(plot_list[[i]])
}

## load this library to use grid.arrange function
library(gridExtra)

## use this function to extract legend:
## source: https://stackoverflow.com/questions/13649473/add-a-common-legend-for-combined-ggplots
## source: https://github.com/hadley/ggplot2/wiki/Share-a-legend-between-two-ggplot2-graphs
g_legend<-function(a.gplot){
   tmp <- ggplot_gtable(ggplot_build(a.gplot))
   leg <- which(sapply(tmp$grobs, function(x) x$name) == "guide-box")
   legend <- tmp$grobs[[leg]]
   return(legend)}

## get legend
mylegend<-g_legend(plot_list[[1]])

## make a final plot
QC_failed_plates <- grid.arrange(arrangeGrob(plot_list[[1]] + theme(legend.position="none") + labs(title = paste("Mutant 20", "\n", "plate 1")) + theme(plot.title = element_text(hjust = 0.5)),
                               plot_list[[2]] + theme(legend.position="none") + labs(title = paste("Mutant 20", "\n", "plate 2")) + theme(plot.title = element_text(hjust = 0.5)),
                               plot_list[[3]] + theme(legend.position="none") + labs(title = paste("Mutant 20", "\n", "plate 3")) + theme(plot.title = element_text(hjust = 0.5)),
                               plot_list[[4]] + theme(legend.position="none") + labs(title = paste("Mutant 20", "\n", "plate 4")) + theme(plot.title = element_text(hjust = 0.5)),
                               plot_list[[5]] + theme(legend.position="none") + labs(title = paste("Mutant 2", "\n", "plate 1")) + theme(plot.title = element_text(hjust = 0.5)),
                               plot_list[[6]] + theme(legend.position="none") + labs(title = paste("Mutant 2", "\n", "plate 2")) + theme(plot.title = element_text(hjust = 0.5)), nrow=2), 
                              mylegend, nrow=2,heights=c(10,2))


## plot
QC_failed_plates
TableGrob (2 x 1) "arrange": 2 grobs
## save
ggsave("/Users/Andy/GCSKO/GCSKO_analysis_git/images_to_export/QC_SS2_failed_plates.png", plot = QC_failed_plates, device = "png", path = NULL, scale = 1, width = 27, height = 25, units = "cm", dpi = 300, limitsize = TRUE)

Add bulk metadata

Add in bulk data predictions

hoo et al.

#Pb Prediction correlations with bulk data (asexual hoo): 

#Load in required package:
library(Hmisc)
#Cooerce expression data into a matrix and load in the reference timecourse data:
x10 <- as.matrix(ss2_mutants_final@assays$RNA@data)
rownames(x10) <- gsub("-", "_", rownames(x10))
#read in bulk data:
hoo<-as.matrix(read.table("/Users/Andy/GCSKO/GCSKO_analysis_git/data/Reference/hoo_berg2.txt",header=T, row.names=1))
#Make a blank dataframe in which to add prediction:
df <- data.frame(matrix(ncol = 4, nrow = 0))
colnames(df) <- c("Prediction(Spearman)","r(Spearman)","Prediction(Pearsons)","r(Pearsons)")
#Do correlations with bulk data using both Spearman and Pearson (and the top 1000 genes):
for (i in 1:ncol(x10))
{
  shared<-intersect(row.names(as.matrix(head(sort(x10[,i], decreasing=TRUE),1000))),row.names(hoo))
  step0<-rcorr(x10[shared,i],hoo[shared,1:12],type = "spearman")
  step1<-as.matrix(t(step0$r[2:13,1]))
  step2<-rcorr(x10[shared,i],hoo[shared,1:12],type = "pearson")
  step3<-as.matrix(t(step2$r[2:13,1]))
  step4<-cbind(colnames(step1)[which.max(step1)],step1[which.max(step1)],colnames(step3)[which.max(step3)],step3[which.max(step3)])
  colnames(step4) <- c("Prediction(Spearman)","r(Spearman)","Prediction(Pearsons)","r(Pearsons)")
  rownames(step4)<-colnames(x10)[i]
  df<-rbind(df,step4)
}
#Write out data into a csv file:
#write.csv(dfringr,file="/Users/ar19/Desktop/PhD/AR04_GCSKO_project/All_mutants_Feb_2018/predictionpbcombined.csv")
#Change the format of the output to make it more readable:
#gsub("Pb_","", dfringr[,1]) - Make predictions into 18hr.dat format:

#spearman:
df[,1] <- gsub("Pb_","", df[,1])
#Remove hr.dat from list:
df[,1] <- gsub("hr.dat","", df[,1])
#Check - dfringr[,1]
#Make into a number:
df[,1] <- as.numeric(df[,1])
df[,2] <- as.numeric(as.character(df[,2]))

#pearson:
df[,3] <- gsub("Pb_","", df[,3])
#Remove hr.dat from list:
df[,3] <- gsub("hr.dat","", df[,3])
#Check - dfringr[,1]
#Make into a number:
df[,3] <- as.numeric(df[,3])
df[,4] <- as.numeric(as.character(df[,4]))
#add to 10X object:
ss2_mutants_final <- AddMetaData(ss2_mutants_final, metadata = df)
Invalid name supplied, making object name syntactically valid. New object name is Prediction.Spearman.r.Spearman.Prediction.Pearsons.r.Pearsons.; see ?make.names for more details on syntax validity

Kasia’s data

Can also do with Kasia’s timecourse data:

kas<-as.matrix(read.table("/Users/Andy/GCSKO/GCSKO_analysis_git/data/Reference/AP2OETC.txt",header=T, row.names=1))
#Make a blank dataframe in which to add prediction:
dfs <- data.frame(matrix(ncol = 4, nrow = 0))
colnames(dfs) <- c("ID","Prediction","r (Pearson)")
#Do correlations with bulk data using both Spearman and Pearson (and the top 1000 genes):
for (i in 1:ncol(x10))
{
  shared<-intersect(row.names(as.matrix(head(sort(x10[,i], decreasing=TRUE),1000))),rownames(kas))
  step0<-rcorr(x10[shared,i],kas[shared,1:10],type = "spearman")
  step1<-as.matrix(t(step0$r[2:11,1]))
  step2<-rcorr(x10[shared,i],kas[shared,1:10],type = "pearson")
  step3<-as.matrix(t(step2$r[2:11,1]))
  step4<-cbind(colnames(step1)[which.max(step1)],step1[which.max(step1)],colnames(step3)[which.max(step3)],step3[which.max(step3)])
  colnames(step4) <- c("Prediction(Spearman)","r(Spearman)","Prediction(Pearsons)","r(Pearsons)")
  rownames(step4)<-colnames(x10)[i]
  dfs<-rbind(dfs,step4)
}
#Write out data into a csv file:
#write.csv(df,file="/Users/ar19/Desktop/PhD/AR04_GCSKO_project/All_mutants_Feb_2018/predictionkasiacombined.csv")

#Change the format of the output to make it more readable:
#gsub("Pb_","", dfs[,1]) - Make predictions into 18hr.dat format:
dfs[,1] <- gsub("X","", dfs[,1])
#Make into a number:
dfs[,1] <- as.numeric(dfs[,1])
#Make into a number:
dfs[,2] <- as.numeric(as.character(dfs[,2]))

#gsub("Pb_","", dfs[,1]) - Make predictions into 18hr.dat format:
dfs[,3] <- gsub("X","", dfs[,3])
#Make into a number:
dfs[,3] <- as.numeric(dfs[,3])
#dfs[,1]
#Make into a number:
dfs[,4] <- as.numeric(as.character(dfs[,4]))

colnames(dfs) <- c('Prediction(Spearman)_Kasia', 'r(Spearman)_Kasia', 'Prediction(Pearson)_Kasia', 'r(Pearson)_Kasia')
#add to Seurat:
#add to 10X object:
ss2_mutants_final <- AddMetaData(ss2_mutants_final, dfs)
Invalid name supplied, making object name syntactically valid. New object name is Prediction.Spearman._Kasiar.Spearman._KasiaPrediction.Pearson._Kasiar.Pearson._Kasia; see ?make.names for more details on syntax validity

Normalisation

normalise and find variable genes

## normalise
ss2_mutants_final <- NormalizeData(ss2_mutants_final, normalization.method = "LogNormalize", scale.factor = 10000)
Performing log-normalization
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
## find variable genes
ss2_mutants_final <- FindVariableFeatures(ss2_mutants_final, selection.method = "vst", nfeatures = 2000)
Calculating gene variances
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Calculating feature variances of standardized and clipped values
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
## make a list of all genes in the dataset
all.genes <- rownames(ss2_mutants_final)

## scale data on all genes
ss2_mutants_final <- ScaleData(ss2_mutants_final, features = all.genes)
Centering and scaling data matrix

  |                                                                             
  |                                                                       |   0%
  |                                                                             
  |============                                                           |  17%
  |                                                                             
  |========================                                               |  33%
  |                                                                             
  |====================================                                   |  50%
  |                                                                             
  |===============================================                        |  67%
  |                                                                             
  |===========================================================            |  83%
  |                                                                             
  |=======================================================================| 100%

Dimensionality reduction

PCA

ss2_mutants_final <- RunPCA(ss2_mutants_final, features = VariableFeatures(object = ss2_mutants_final), verbose = FALSE)

PCA plot

DimPlot(ss2_mutants_final, reduction = "pca", group.by = "sub_identity_updated")

ElbowPlot(ss2_mutants_final, ndims = 30, reduction = "pca")

Find clusters

ss2_mutants_final <- FindNeighbors(ss2_mutants_final, dims = 1:21)
Computing nearest neighbor graph
Computing SNN
ss2_mutants_final <- FindClusters(ss2_mutants_final, resolution = 1)
Modularity Optimizer version 1.3.0 by Ludo Waltman and Nees Jan van Eck

Number of nodes: 2970
Number of edges: 97436

Running Louvain algorithm...
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Maximum modularity in 10 random starts: 0.8634
Number of communities: 18
Elapsed time: 0 seconds

UMAP

Improve UMAP

#old way of running UMAP:
#ss2_mutants_final <-RunUMAP(ss2_mutants_final, reduction = "pca", dims = 1:10, n.neighbors = 150, seed.use = 1234, min.dist = 0.4, repulsion.strength = 0.03, local.connectivity = 150)
ss2_mutants_final <- RunUMAP(ss2_mutants_final, dims = 1:12)
20:09:17 UMAP embedding parameters a = 0.9922 b = 1.112
Found more than one class "dist" in cache; using the first, from namespace 'spam'
Also defined by ‘BiocGenerics’
20:09:17 Read 2970 rows and found 12 numeric columns
20:09:17 Using Annoy for neighbor search, n_neighbors = 30
Found more than one class "dist" in cache; using the first, from namespace 'spam'
Also defined by ‘BiocGenerics’
20:09:17 Building Annoy index with metric = cosine, n_trees = 50
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
20:09:18 Writing NN index file to temp file /var/folders/wj/rztzclxn1t10cl2sk0plbf3r0000gn/T//RtmpXGhNV1/file43372c318018
20:09:18 Searching Annoy index using 1 thread, search_k = 3000
20:09:19 Annoy recall = 100%
20:09:21 Commencing smooth kNN distance calibration using 1 thread
20:09:23 Initializing from normalized Laplacian + noise
20:09:23 Commencing optimization for 500 epochs, with 117082 positive edges
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
20:09:29 Optimization finished
p1 <- DimPlot(ss2_mutants_final, group.by = "ident", label = TRUE)
p2 <- DimPlot(ss2_mutants_final, group.by = "identity_updated")
p1 + p2

Cluster assignment

Interactive

plot <- FeaturePlot(ss2_mutants_final, features = "nFeature_RNA")   

HoverLocator(plot = plot, information = FetchData(ss2_mutants_final, vars = c("nFeature_RNA", "ident", "identity_updated")))
the condition has length > 1 and only the first element will be usedthe condition has length > 1 and only the first element will be used`error_y.color` does not currently support multiple values.`error_x.color` does not currently support multiple values.`line.color` does not currently support multiple values.The titlefont attribute is deprecated. Use title = list(font = ...) instead.the condition has length > 1 and only the first element will be usedthe condition has length > 1 and only the first element will be used`error_y.color` does not currently support multiple values.`error_x.color` does not currently support multiple values.`line.color` does not currently support multiple values.The titlefont attribute is deprecated. Use title = list(font = ...) instead.

ngenes, nmito, ncounts visualisation

## add column to log counts so they are easier to visualise
ss2_mutants_final <- AddMetaData(ss2_mutants_final, log10(ss2_mutants_final@meta.data$nCount_RNA), col.name = "nCount_log10")

FeaturePlot(ss2_mutants_final, features = c("nCount_RNA", "nCount_log10", "nFeature_RNA", "percent.mt"))   

Violin plots cluster-by-cluster:

VlnPlot(object = ss2_mutants_final, features = "nFeature_RNA", pt.size = 0.01) +
  labs(x="Cluster",
       y="Genes per Cell",
       title = "Number of Genes per Cell") +
  theme(legend.position = "none")


VlnPlot(object = ss2_mutants_final, features = "nCount_log10", pt.size = 0.01) +
  labs(x="Cluster",
       y="Log10(Counts per Cell)",
       title = "Number of Counts per Cell") +
  theme(legend.position = "none")


VlnPlot(object = ss2_mutants_final, features = "percent.mt", pt.size = 0.01) +
  labs(x="Cluster",
       y="% Mitochondrial Reads",
       title = "Percentage of Mitochondrial Reads per Cell") +
  theme(legend.position = "none")

Expression of marker genes

# PBANKA-0515000 - p25 - female
# PBANKA-1319500 - CCP2 - female - used in 820 line
# PBANKA-1212600 - HAP2 - male
# PBANKA-0600600 - NEK3 - male
# PBANKA-1315700 - RON2 - (asexuals and some male?)
# "PBANKA-0416100" - dynenin heavy chain - male - used in 820 line
# PBANKA-1437500 - AP2-G - seuxal commitment gene
# PBANKA-0831000 - MSP1 - late asexual
# PBANKA-1102200 - MSP8 - early asexual (from Bozdech paper)
FeaturePlot(ss2_mutants_final, features = c("PBANKA-0515000", "PBANKA-1319500", "PBANKA-1212600","PBANKA-0600600", "PBANKA-1315700", "PBANKA-0416100", "PBANKA-1437500", "PBANKA-0831000", "PBANKA-1102200"), coord.fixed = TRUE)

Dotplot

This essentially allows us to view which genotypes sit in which clusters. Where we see that WT is not present, we can presume that this mutant has a unique transcriptome (either from the whole WT trajectory or it has arrested and so represents a WT developing form - we can find this out in the next stage of analaysis when we integrate with 10X data).

df_meta_data <- as.data.frame(ss2_mutants_final@meta.data)

dot_plot_df <- as.data.frame.matrix(table(df_meta_data$RNA_snn_res.1, df_meta_data$identity_updated))

dot_plot_df_pc <- (as.data.frame.matrix(prop.table(table(df_meta_data$RNA_snn_res.1, df_meta_data$identity_updated), margin = 2)) * 100)

dot_plot_df_pc$cluster <- rownames(dot_plot_df_pc)
library(dplyr)
dot_plot_df_pc_mutated <- mutate(dot_plot_df_pc)
library(reshape2)
dot_plot_df_pc_melted <- melt(dot_plot_df_pc, variable.name = "cluster")
colnames(dot_plot_df_pc_melted)[2] <- "identity"
df_meta_data <- as.data.frame(ss2_mutants_final@meta.data)

dot_plot_df <- as.data.frame.matrix(table(df_meta_data$RNA_snn_res.1, df_meta_data$identity_updated))

dot_plot_df_pc <- (as.data.frame.matrix(prop.table(table(df_meta_data$RNA_snn_res.1, df_meta_data$identity_updated), margin = 2)) * 100)

dot_plot_df_pc$cluster <- rownames(dot_plot_df_pc)
library(dplyr)
dot_plot_df_pc_mutated <- mutate(dot_plot_df_pc)
library(reshape2)
dot_plot_df_pc_melted <- melt(dot_plot_df_pc, variable.name = "cluster")
Using cluster as id variables
colnames(dot_plot_df_pc_melted)[2] <- "identity"

Mutants 3, 2, and 13 all seem to display this unique phenotype.

expression of 820 markers

library(ggplot2)
  p = ggplot(dot_plot_df_pc_melted,
             aes(y = factor(cluster),
                 x = factor(identity))) +
      geom_point(aes(colour=value, size=value)) + 
      scale_color_gradient(low="blue", high="red", limits=c( 1, max(dot_plot_df_pc_melted$value)), na.value="white") +
      theme_bw() +
      theme(panel.grid.major=element_blank(), panel.grid.minor=element_blank())
  p = p +
      ylab("Cluster") +
      xlab("Identity") +
      theme(axis.text.x=element_text(size=12, face="italic", angle=45, hjust=1)) + 
      theme(axis.text.y=element_text(size=12, face="italic"))
  print(p)

Confirm life cycle designations using bulk correlations

## make plots 
plots <- FeaturePlot(ss2_mutants_final, features = c("PBANKA-1319500", "PBANKA-0416100"), blend = TRUE, combine = FALSE, coord.fixed = TRUE)

# Get just the co-expression plot, built-in legend is meaningless for this plot
#plots[[3]] + NoLegend()  

# Get just the key
#plots[[4]] 

# Stitch the co-expression and key plots together
plots[[3]] + NoLegend() + plots[[4]]/plot_spacer() + plot_layout(widths = c(2,1))

4. Cluster together with MCA data

Prepare

set up MCA data

FeaturePlot(ss2_mutants_final, features = c("Prediction.Spearman._Kasia", "Prediction.Spearman."))

set up MCA object

mca object

## read in data
counts_mca <- read.table("/Users/Andy/GCSKO/GCSKO_analysis_git/data/Reference/allcounts4.csv", header = TRUE, sep = ",", row.names=1, stringsAsFactors = TRUE)
dim(counts_mca)
[1] 5245 2432
anno_mca <- read.delim("/Users/Andy/GCSKO/GCSKO_analysis_git/data/Reference/allpheno8.2.csv", header = TRUE, sep = ",", row.names=1)
dim(anno_mca)
[1] 2432   49
## subset all blood stage cells
## find blood stages
blood_stages <- c("Merozoite", "Shz", "Male", "Schizont", "Female", "Trophozoite", "Ring")

blood_stage_cell_names <- rownames(anno_mca[anno_mca$ShortenedLifeStage2 %in% blood_stages, ])

## subset dataframes
counts_mca_blood_stage <- counts_mca[ ,colnames(counts_mca) %in% blood_stage_cell_names]
dim(counts_mca_blood_stage)
[1] 5245 1150
anno_mca_blood_stage <- anno_mca[rownames(anno_mca) %in% blood_stage_cell_names, ]
dim(anno_mca_blood_stage)
[1] 1150   49
## remove control cells:
non_control_cell_names <- rownames(anno_mca_blood_stage[anno_mca_blood_stage$Number_of_cells == 1, ])
counts_mca_blood_stage <- counts_mca_blood_stage[ ,colnames(counts_mca_blood_stage) %in% non_control_cell_names]
dim(counts_mca_blood_stage)
[1] 5245 1093
anno_mca_blood_stage <- anno_mca_blood_stage[rownames(anno_mca_blood_stage) %in% non_control_cell_names, ]
dim(anno_mca_blood_stage)
[1] 1093   49
## check
identical(rownames(counts_mca_blood_stage), rownames(counts))
[1] TRUE

n.b. a filter of 40 allows the merozoites to complete the ring in the asexuals

## make Seurat object with same filtering as main object because they are sequenced to same depth:
GCSKO_mca <- CreateSeuratObject(counts = counts_mca_blood_stage, meta.data = anno_mca_blood_stage, min.cells = 0, min.features = 120, project = "GCSKO")
Feature names cannot have underscores ('_'), replacing with dashes ('-')
GCSKO_mca
An object of class Seurat 
5245 features across 999 samples within 1 assay 
Active assay: RNA (5245 features, 0 variable features)
GCSKO_mca@meta.data$experiment <- "mca"
ss2_mutants_final@meta.data$experiment <- "ss2_mutants"

normalise object

VlnPlot(object = GCSKO_mca, features = "nFeature_RNA", pt.size = 0.01) +
  labs(x="Cluster",
       y="Genes per Cell",
       title = "Number of Genes per Cell") +
  theme(legend.position = "none") + geom_hline(yintercept=220)


VlnPlot(object = GCSKO_mca, features = "nCount_RNA", pt.size = 0.01) +
  labs(x="Cluster",
       y="Log10(Counts per Cell)",
       title = "Number of Counts per Cell") +
  theme(legend.position = "none")

Integrate

## normalise
GCSKO_mca <- NormalizeData(GCSKO_mca, normalization.method = "LogNormalize", scale.factor = 10000)
Performing log-normalization
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
## find variable genes
GCSKO_mca <- FindVariableFeatures(GCSKO_mca, selection.method = "vst", nfeatures = 2000)
Calculating gene variances
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Calculating feature variances of standardized and clipped values
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
## make a list of all genes in the dataset
all.genes <- rownames(GCSKO_mca)
## scale data on all genes
GCSKO_mca <- ScaleData(GCSKO_mca, features = all.genes)
Centering and scaling data matrix

  |                                                                             
  |                                                                       |   0%
  |                                                                             
  |============                                                           |  17%
  |                                                                             
  |========================                                               |  33%
  |                                                                             
  |====================================                                   |  50%
  |                                                                             
  |===============================================                        |  67%
  |                                                                             
  |===========================================================            |  83%
  |                                                                             
  |=======================================================================| 100%

Analyse

Scale and PCA

## make list
ss2.mca.list <- list(GCSKO_mca, ss2_mutants_final)
ss2.mca.anchors <- FindIntegrationAnchors(object.list = ss2.mca.list, dims = 1:21, verbose = FALSE)
ss2.mca.integrated <- IntegrateData(anchorset = ss2.mca.anchors, dims = 1:21, verbose = FALSE, features.to.integrate = all.genes)
Adding a command log without an assay associated with it

Inspect PCS:

# set during IntegrateData
DefaultAssay(ss2.mca.integrated) <- "integrated"
# Run the standard workflow for visualization and clustering
ss2.mca.integrated <- ScaleData(ss2.mca.integrated, verbose = FALSE)
ss2.mca.integrated <- RunPCA(ss2.mca.integrated, npcs = 30, verbose = FALSE)

UMAP

## run UMAP
ss2.mca.integrated <- RunUMAP(ss2.mca.integrated, reduction = "pca", dims = 1:15)
20:11:28 UMAP embedding parameters a = 0.9922 b = 1.112
Found more than one class "dist" in cache; using the first, from namespace 'spam'
Also defined by ‘BiocGenerics’
20:11:28 Read 3969 rows and found 15 numeric columns
20:11:28 Using Annoy for neighbor search, n_neighbors = 30
Found more than one class "dist" in cache; using the first, from namespace 'spam'
Also defined by ‘BiocGenerics’
20:11:28 Building Annoy index with metric = cosine, n_trees = 50
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
20:11:30 Writing NN index file to temp file /var/folders/wj/rztzclxn1t10cl2sk0plbf3r0000gn/T//RtmpXGhNV1/file4337275d142d
20:11:30 Searching Annoy index using 1 thread, search_k = 3000
20:11:31 Annoy recall = 100%
20:11:33 Commencing smooth kNN distance calibration using 1 thread
20:11:35 Initializing from normalized Laplacian + noise
20:11:36 Commencing optimization for 500 epochs, with 159194 positive edges
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
20:11:43 Optimization finished
## add new column 
ss2.mca.integrated@meta.data$clusters_integrated <- ss2.mca.integrated@meta.data$seurat_clusters

ss2.mca.integrated@meta.data$clusters_integrated <- ifelse(is.na(ss2.mca.integrated@meta.data$clusters_integrated), ss2.mca.integrated@meta.data$ShortenedLifeStage2, ss2.mca.integrated@meta.data$clusters_integrated)

DimPlot(ss2.mca.integrated, pt.size = 0.01, label = TRUE, split.by = "experiment", group.by = "clusters_integrated") + coord_fixed() + theme_void()

ElbowPlot(ss2.mca.integrated, ndims = 30, reduction = "pca")

cluster

generate clusters:

VlnPlot(object = ss2.mca.integrated, features = "nFeature_RNA", pt.size = 0.01) + geom_hline(yintercept=100)

Save

save counts and pheno without anopheles and control cells

## copy old clusters
#ss2.mca.integrated <- AddMetaData(ss2.mca.integrated, ss2.mca.integrated@meta.data$RNA_snn_res.1, col.name = "pre_integration_clusters")

## generate new clusters
#ss2.mca.integrated <- FindNeighbors(ss2.mca.integrated, dims = 1:21)
#ss2.mca.integrated <- FindClusters(ss2.mca.integrated, resolution = 1, random.seed = 42, algorithm = 2)

save counts and pheno objects

write.csv(counts, file = "/Users/Andy/GCSKO/GCSKO_analysis_git/data_to_export/counts_2020_filtered.csv")
write.csv(pheno, file = "/Users/Andy/GCSKO/GCSKO_analysis_git/data_to_export/pheno_2020_filtered.csv")

save the session objects

pheno_filtered_cells <- ss2_mutants_final@meta.data
counts_filtered_cells <- ss2_mutants_final@assays$RNA@counts

write.csv(counts_filtered_cells, file = "/Users/Andy/GCSKO/GCSKO_analysis_git/data_to_export/counts_post_qc.csv")
write.csv(pheno_filtered_cells, file = "/Users/Andy/GCSKO/GCSKO_analysis_git/data_to_export/pheno_post_qc.csv")

Appendix

Session Info

LS0tCnN1YnRpdGxlOiAnR2FtZXRvY3l0ZSBEZXZlbG9wbWVudCBpbiA8aT5QbGFzbW9kaXVtIGJlcmdoZWk8L2k+Jwp0aXRsZTogfAogICFbXSgvVXNlcnMvQW5keS9HQ1NLTy9HQ1NLT19hbmFseXNpc19naXQvR0NTS09fbG9nby5qcGcpe3dpZHRoPTMwMHB4fSAgCiAgU21hcnQtc2VxMiBRdWFsaXR5IENvbnRyb2wKYXV0aG9yOiAiW0FuZHJldyBSdXNzZWxsXShodHRwczovL2FqY3J1c3NlbGwud2l4c2l0ZS5jb20vbXlzaXRlL2Fib3V0KSIKaW5zdGl0dXRlOiBXZWxsY29tZSBTYW5nZXIgSW5zdGl0dXRlCmRhdGU6ICdgciBmb3JtYXQoU3lzLkRhdGUoKSwgIiVCICVkLCAlWSIpYCcKb3V0cHV0OgogIGh0bWxfbm90ZWJvb2s6CiAgICB0aGVtZTogY29zbW8KICAgIHRvYzogeWVzCiAgICB0b2NfZGVwdGg6IDMKICAgICN0b2NfZmxvYXQ6IHllcwogICAgZGZfcHJpbnQ6IHBhZ2VkCi0tLQoKKioqCiMgMS4gUmVhZCBpbiB0aGUgZGF0YSAgey50YWJzZXR9CgojIyMgTG9hZCB0aGUgcmVxdWlyZWQgcGFja2FnZXMKCmBgYHtyIGxvYWQgcGFja2FnZXMsIGVjaG8gPSBGQUxTRX0KCiMjIFNldXJhdCBpcyBuZWVkZWQgZm9yIG1vc3Qgb2YgdGhpcyBzY3JpcHQKaWYocmVxdWlyZSgiU2V1cmF0IiwgcXVpZXRseSA9IFRSVUUpKXsKICAgIHByaW50KCJTZXVyYXQgaXMgbG9hZGVkIGNvcnJlY3RseSIpCn0gZWxzZSB7CiAgICBwcmludCgidHJ5aW5nIHRvIGluc3RhbGwgU2V1cmF0IikKICAgIGluc3RhbGwucGFja2FnZXMoIlNldXJhdCIpCiAgICBpZihyZXF1aXJlKFNldXJhdCkpewogICAgICAgIHByaW50KCJTZXVyYXQgaW5zdGFsbGVkIGFuZCBsb2FkZWQiKQogICAgfSBlbHNlIHsKICAgICAgICBzdG9wKCJjb3VsZCBub3QgaW5zdGFsbCBTZXVyYXQiKQogICAgfQp9CgojIyB2aXJpZGlzIGlzIG5lZWRlZCB0byBjb2xvdXIgZGF0YSBpbiBwbG90cwppZihyZXF1aXJlKCJ2aXJpZGlzIiwgcXVpZXRseSA9IFRSVUUpKXsKICAgIHByaW50KCJ2aXJpZGlzIGlzIGxvYWRlZCBjb3JyZWN0bHkiKQp9IGVsc2UgewogICAgcHJpbnQoInRyeWluZyB0byBpbnN0YWxsIHZpcmlkaXMiKQogICAgaW5zdGFsbC5wYWNrYWdlcygidmlyaWRpcyIpCiAgICBpZihyZXF1aXJlKHZpcmlkaXMpKXsKICAgICAgICBwcmludCgidmlyaWRpcyBpbnN0YWxsZWQgYW5kIGxvYWRlZCIpCiAgICB9IGVsc2UgewogICAgICAgIHN0b3AoImNvdWxkIG5vdCBpbnN0YWxsIHZpcmlkaXMiKQogICAgfQp9CgojIyBnZ3B1YnIgaXMgbmVlZGVkIGZvciBwbG90dGluZwppZihyZXF1aXJlKCJnZ3B1YnIiLCBxdWlldGx5ID0gVFJVRSkpewogICAgcHJpbnQoImdncHViciBpcyBsb2FkZWQgY29ycmVjdGx5IikKfSBlbHNlIHsKICAgIHByaW50KCJ0cnlpbmcgdG8gaW5zdGFsbCBnZ3B1YnIiKQogICAgaW5zdGFsbC5wYWNrYWdlcygiZ2dwdWJyIikKICAgIGlmKHJlcXVpcmUoZ2dwdWJyKSl7CiAgICAgICAgcHJpbnQoImdncHViciBpbnN0YWxsZWQgYW5kIGxvYWRlZCIpCiAgICB9IGVsc2UgewogICAgICAgIHN0b3AoImNvdWxkIG5vdCBpbnN0YWxsIGdncHViciIpCiAgICB9Cn0KCiMjIGNvd3Bsb3QgaXMgbmVlZGVkIGZvciBwbG90dGluZwppZihyZXF1aXJlKCJjb3dwbG90IiwgcXVpZXRseSA9IFRSVUUpKXsKICAgIHByaW50KCJjb3dwbG90IGlzIGxvYWRlZCBjb3JyZWN0bHkiKQp9IGVsc2UgewogICAgcHJpbnQoInRyeWluZyB0byBpbnN0YWxsIGNvd3Bsb3QiKQogICAgaW5zdGFsbC5wYWNrYWdlcygiY293cGxvdCIpCiAgICBpZihyZXF1aXJlKGNvd3Bsb3QpKXsKICAgICAgICBwcmludCgiY293cGxvdCBpbnN0YWxsZWQgYW5kIGxvYWRlZCIpCiAgICB9IGVsc2UgewogICAgICAgIHN0b3AoImNvdWxkIG5vdCBpbnN0YWxsIGNvd3Bsb3QiKQogICAgfQp9CgojIyBnZ3Bsb3QyYmRjIGlzIG5lZWRlZCBmb3IgcGxvdHRpbmcgcGxhdGUgbWFwcwppZihyZXF1aXJlKCJnZ3Bsb3QyYmRjIiwgcXVpZXRseSA9IFRSVUUpKXsKICAgIHByaW50KCJnZ3Bsb3QyYmRjIGlzIGxvYWRlZCBjb3JyZWN0bHkiKQp9IGVsc2UgewogICAgcHJpbnQoInRyeWluZyB0byBpbnN0YWxsIGdncGxvdDJiZGMiKQogICAgaWYoIXJlcXVpcmUoImRldnRvb2xzIikpIGluc3RhbGwucGFja2FnZXMoImRldnRvb2xzIikKICAgIGRldnRvb2xzOjppbnN0YWxsX2dpdGh1YigiYnJpYW5kY29ubmVsbHkvZ2dwbG90MmJkYyIpCiAgICBpZihyZXF1aXJlKGdncGxvdDJiZGMpKXsKICAgICAgICBwcmludCgiZ2dwbG90MmJkYyBpbnN0YWxsZWQgYW5kIGxvYWRlZCIpCiAgICB9IGVsc2UgewogICAgICAgIHN0b3AoImNvdWxkIG5vdCBpbnN0YWxsIGdncGxvdDJiZGMiKQogICAgfQp9CgojIyBwYXRjaHdvcmsgaXMgbmVlZGVkIGZvciBwbG90dGluZwojIyBXQVJOSU5HISBjb3dwbG90IG92ZXItcmlkZXMgdGhpcyBieSBtYXNraW5nIGl0IHNvIGJlIGNhcmVmdWwuCmlmKHJlcXVpcmUoInBhdGNod29yayIsIHF1aWV0bHkgPSBUUlVFKSl7CiAgICBwcmludCgicGF0Y2h3b3JrIGlzIGxvYWRlZCBjb3JyZWN0bHkiKQp9IGVsc2UgewogICAgcHJpbnQoInRyeWluZyB0byBpbnN0YWxsIHBhdGNod29yayIpCiAgICBpbnN0YWxsLnBhY2thZ2VzKCJwYXRjaHdvcmsiKQogICAgaWYocmVxdWlyZShwYXRjaHdvcmspKXsKICAgICAgICBwcmludCgicGF0Y2h3b3JrIGluc3RhbGxlZCBhbmQgbG9hZGVkIikKICAgIH0gZWxzZSB7CiAgICAgICAgc3RvcCgiY291bGQgbm90IGluc3RhbGwgcGF0Y2h3b3JrIikKICAgIH0KfQoKIyMgbG9hZCBpbiBkcGx5ciAKbGlicmFyeShkcGx5cikgI2ZvciBtdXRhdGluZyB0YWJsZQoKYGBgCgojIyMgSW1wb3J0IEdURiBmaWxlCgpUaGlzIHdpbGwgYmUgaGVscGZ1bCBsYXRlciBvbi4gVGhpcyBjb250YWlucyBhbm5vdGF0aW9ucyBmb3IgZWFjaCBnZW5lOgpgYGB7ciBpbXBvcnQgR1RGfQojI0ltcG9ydCBndGYgZmlsZToKZ3RmIDwtIHJlYWQudGFibGUoIi9Vc2Vycy9BbmR5L0dDU0tPL0dDU0tPX2FuYWx5c2lzX2dpdC9kYXRhL1JlZmVyZW5jZS9QYmVyZ2hlaS5ndGYiLCBzZXA9Ilx0IiwgaGVhZGVyID0gRkFMU0UpCgojIyBpbnNwZWN0CmhlYWQoZ3RmKQpgYGAKKk4uQi5UaGlzIHdhcyB0aGUgLmd0ZiBmaWxlIHVzZWQgZm9yIGZlYXR1cmUgY291bnRpbmcgdGhlIGRhdGEKCiMjIyBJbXBvcnQgQ291bnRzIGFuZCBQaGVubyBmaWxlcwoKYGBge3IgaW1wb3J0IGRhdGF9CiMjIHJlYWQgaW4gY291bnRzCmNvdW50cyA8LSByZWFkLmRlbGltKCIvVXNlcnMvQW5keS9HQ1NLTy9HQ1NLT19hbmFseXNpc19naXQvZGF0YS9TbWFydHNlcTIvY291bnRzXzIwMjAuY3N2Iiwgc2VwID0gIiwiLCBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UsIHJvdy5uYW1lcyA9IDEpCgojIyByZWFkIGluIHBoZW5vCnBoZW5vIDwtIHJlYWQuZGVsaW0oIi9Vc2Vycy9BbmR5L0dDU0tPL0dDU0tPX2FuYWx5c2lzX2dpdC9kYXRhL1NtYXJ0c2VxMi9waGVub18yMDIwLmNzdiIsIHNlcCA9ICIsIiwgc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFKQoKIyMgY2hlY2sgZGltZW5zaW9ucyBvZiBib3RoCmV4cGVjdGVkX251bWJlcl9vZl9jZWxscyA8LSAoIDM4NCAqIDEyKQpwYXN0ZSgiVGhlIGV4cGVjdGVkIG51bWJlciBvZiBjZWxscyBpcyIsIGV4cGVjdGVkX251bWJlcl9vZl9jZWxscykKcGFzdGUoIm51bWJlciBvZiBnZW5lcyBpbiBjb3VudHMiLCBkaW0oY291bnRzKVsxXSwgIm51bWJlciBvZiBjZWxscyBpbiBjb3VudHMiLCBkaW0oY291bnRzKVsyXSkKcGFzdGUoIm51bWJlciBvZiBjb2x1bW5zIGluIGNvdW50cyIsIGRpbShwaGVubylbMl0sICJudW1iZXIgb2YgY2VsbHMgaW4gcGhlbm8iLCBkaW0ocGhlbm8pWzFdKQoKIyMgbWFrZSByb3duYW1lcyB0aGUgc2FtcGxlX2lkIGluIHBoZW5vCnJvd25hbWVzKHBoZW5vKSA8LSBwaGVubyRzYW1wbGVfaWQKCiMjIGNoZWNrIHRoYXQgdGhlIG5hbWVzIGFyZSB0aGUgc2FtZQpwYXN0ZSgiQXJlIHRoZSBuYW1lcyB0aGUgc2FtZT8iKQp0YWJsZSgoY29sbmFtZXMoY291bnRzKSAlaW4lIHJvd25hbWVzKHBoZW5vKSkpCmBgYAoKIyMjIFJlbW92ZSBBbm9waGVsZXMgY2VsbHMKClRoZXNlIGNlbGxzIHdlcmUgaW5jbHVkZWQgaW4gb25lIG9mIHRoZSBzZXF1ZW5jaW5nIHJ1bnMgYW5kIGFyZSBpcnJlbGV2YW50LgpgYGB7ciByZW1vdmUgYW5vcGhlbGVzfQojIyBnZXQgcmlkIG9mIHRoZSBjZWxscyBieSBmaW5kaW5nIGFsbCB0aGUgY2VsbHMgdGhhdCBoYXZlIEFzIGluIHRoZWlyIHNwZWNpZXMgY29sCm5hbWVzX29mX21vc3F1aXRvX2NlbGxzIDwtIHJvd25hbWVzKHBoZW5vWyhwaGVubyRzcGVjaWVzID09ICJBcyIpLCBdKQoKIyMgd2hpY2ggZ2l2ZXMKdGFibGUoY29sbmFtZXMoY291bnRzKSAlaW4lIG5hbWVzX29mX21vc3F1aXRvX2NlbGxzKQoKIyMgc3Vic2V0IApjb3VudHMgPC0gY291bnRzWywtd2hpY2goY29sbmFtZXMoY291bnRzKSAlaW4lIG5hbWVzX29mX21vc3F1aXRvX2NlbGxzKV0KcGhlbm8gPC0gcGhlbm9bLSh3aGljaChyb3duYW1lcyhwaGVubykgJWluJSBuYW1lc19vZl9tb3NxdWl0b19jZWxscykpLCBdCgojIyBjaGVjayBkaW1lbnNpb25zCnBhc3RlKCJudW1iZXIgb2YgZ2VuZXMgaW4gY291bnRzIiwgZGltKGNvdW50cylbMV0sICJudW1iZXIgb2YgY2VsbHMgaW4gY291bnRzIiwgZGltKGNvdW50cylbMl0pCnBhc3RlKCJudW1iZXIgb2YgY29sdW1ucyBpbiBjb3VudHMiLCBkaW0ocGhlbm8pWzJdLCAibnVtYmVyIG9mIGNlbGxzIGluIHBoZW5vIiwgZGltKHBoZW5vKVsxXSkKYGBgCgojIyMgUmVtb3ZlIGNvbnRyb2wgY2VsbHM6CmBgYHtyIHJlbW92ZSBjb250cm9sc30KIyMgZmluZCBhbGwgY2VsbHMgdGhhdCBhcmUgbGFiZWxsZWQgYXMgc3VjaApuYW1lc19vZl9jb250cm9sX2NlbGxzIDwtIHJvd25hbWVzKHBoZW5vWyhwaGVubyRpc19jb250cm9sID09ICJUUlVFIiksIF0pCgojIyB3aGljaCBnaXZlcwp0YWJsZShjb2xuYW1lcyhjb3VudHMpICVpbiUgbmFtZXNfb2ZfY29udHJvbF9jZWxscykKCiMjIHN1YnNldCAKY291bnRzIDwtIGNvdW50c1ssLXdoaWNoKGNvbG5hbWVzKGNvdW50cykgJWluJSBuYW1lc19vZl9jb250cm9sX2NlbGxzKV0KcGhlbm8gPC0gcGhlbm9bLSh3aGljaChyb3duYW1lcyhwaGVubykgJWluJSBuYW1lc19vZl9jb250cm9sX2NlbGxzKSksIF0KCiMjIGNoZWNrIGRpbWVuc2lvbnMKcGFzdGUoIm51bWJlciBvZiBnZW5lcyBpbiBjb3VudHMiLCBkaW0oY291bnRzKVsxXSwgIm51bWJlciBvZiBjZWxscyBpbiBjb3VudHMiLCBkaW0oY291bnRzKVsyXSkKcGFzdGUoIm51bWJlciBvZiBjb2x1bW5zIGluIGNvdW50cyIsIGRpbShwaGVubylbMl0sICJudW1iZXIgb2YgY2VsbHMgaW4gcGhlbm8iLCBkaW0ocGhlbm8pWzFdKQpgYGAKCiMjIyBSZW1vdmUgMTAgYW5kIDI3CgoxMCBhbmQgMjcgZmFpbGVkIGdlbm90eXBpbmcgYW5kIHNvIHdpbGwgYmUgcmVtb3ZlZApgYGB7ciByZW1vdmUgMTAgYW5kIDI3fQojIyBmaW5kIGFsbCBjZWxscyB0aGF0IGFyZSBsYWJlbGxlZCBhcyBzdWNoCm5hbWVzX29mX2dlbm90eXBlX2ZhaWxfY2VsbHMgPC0gcm93bmFtZXMocGhlbm9bKHBoZW5vJHN1Yl9pZGVudGl0eV91cGRhdGVkICVpbiUgYygiR0NTS08tMTAiLCAiV1QtMTAiLCAiR0NTS08tMjciKSksIF0pCgojIyB3aGljaCBnaXZlcwp0YWJsZShjb2xuYW1lcyhjb3VudHMpICVpbiUgbmFtZXNfb2ZfZ2Vub3R5cGVfZmFpbF9jZWxscykKCiMjIHN1YnNldCAKY291bnRzIDwtIGNvdW50c1ssLXdoaWNoKGNvbG5hbWVzKGNvdW50cykgJWluJSBuYW1lc19vZl9nZW5vdHlwZV9mYWlsX2NlbGxzKV0KcGhlbm8gPC0gcGhlbm9bLSh3aGljaChyb3duYW1lcyhwaGVubykgJWluJSBuYW1lc19vZl9nZW5vdHlwZV9mYWlsX2NlbGxzKSksIF0KCiMjIGNoZWNrIGRpbWVuc2lvbnMKcGFzdGUoIm51bWJlciBvZiBnZW5lcyBpbiBjb3VudHMiLCBkaW0oY291bnRzKVsxXSwgIm51bWJlciBvZiBjZWxscyBpbiBjb3VudHMiLCBkaW0oY291bnRzKVsyXSkKcGFzdGUoIm51bWJlciBvZiBjb2x1bW5zIGluIGNvdW50cyIsIGRpbShwaGVubylbMl0sICJudW1iZXIgb2YgY2VsbHMgaW4gcGhlbm8iLCBkaW0ocGhlbm8pWzFdKQpgYGAKCiMjIyBGaWx0ZXIgbm9uLWdlbmVzIG91dCBvZiBjb3VudHMKCkZpbHRlciBvdXQgdGhlIFFDIGNvbHVtbnMgY29udGFpbmVkIGluIGNvdW50cyB0aGF0IGRvIG5vdCBjb3JyZXNwb25kIHRvIGdlbmVzCmBgYHtyIGNsZWFuIGNvdW50c30KIyMgc2luY2UgdGhlIGRhdGF0YWJsZSBjdXJyZW50bHkgY29udGFpbnM6CnBhc3RlKCJUaGUgY3VycmVudCBjb3VudHMgdGFibGUgY29udGFpbnMgdGhlc2Ugbm9uLWdlbmUgcm93czoiKQpyb3duYW1lcyhjb3VudHNbLShncmVwKCJQQkFOS0EqIiwgcm93bmFtZXMoY291bnRzKSkpLCBdKQoKIyMgc3Vic2V0CiMgbWFrZSBhIGNvcHkgb2YgY291bnRzIGp1c3QgaW4gY2FzZSB0aGF0IGluZm8gaXMgdXNlZnVsIGluIGZ1dHVyZSBhbmFseXNpcwpjb3VudHNfZ2VuZXMgPC0gY291bnRzCiMgcmVtb3ZlIG5vbi1nZW5lIHJvd3MKY291bnRzIDwtIGNvdW50c1soZ3JlcCgiUEJBTktBKiIsIHJvd25hbWVzKGNvdW50cykpKSwgXQojY2hlY2sKcGFzdGUoIm51bWJlciBvZiBnZW5lcyBpbiBjb3VudHMiLCBkaW0oY291bnRzKVsxXSwgIm51bWJlciBvZiBjZWxscyBpbiBjb3VudHMiLCBkaW0oY291bnRzKVsyXSkKYGBgCgpUaGlzIDUyNDUgaW5jbHVkZXMgYWxsIHR5cGVzIG9mIGdlbmVzOgpgYGB7ciBnZW5lIGNvdW50fQojIyBjaGVjayBzaXplCnBhc3RlKCJUaGUgZGltZW5zaW9ucyBvZiB0aGUgR1RGIGZpbGUgYXJlOiIpCmRpbShndGZbLXdoaWNoKGd0ZiRWMyA9PSAiQ0RTIiksXSkKCiMjIGxvb2sgYXQgcG9zc2libGUgdHlwZXMgb2YgZ2VuZXMKcGFzdGUoIlRoZSB0eXBlcyBvZiBnZW5lcyBpbiB0aGUgZGF0YWZyYW1lIGFyZToiKQpuYW1lcyh0YWJsZShndGYkVjMpKQpgYGAKCioqKgojIDIuIEZpbHRlcmluZyB7LnRhYnNldH0KCiMjIyBzZXQtdXAgZGF0YQoKbWFrZSBzZXVyYXQgb2JqZWN0CmBgYHtyIG1ha2Ugc2V1cmF0fQojIyBtYWtlIHNldXJhdCBvYmplY3QKc3MyX211dGFudHMgPC0gQ3JlYXRlU2V1cmF0T2JqZWN0KGNvdW50cyA9IGNvdW50cywgcHJvamVjdCA9ICJHQ1NLTyIsIG1pbi5jZWxscyA9IDAsIG1pbi5mZWF0dXJlcyA9IDEsIG1ldGEuZGF0YSA9IHBoZW5vKQojIyBuLmIuIGNlbGxzIG11c3QgaGF2ZSBhdCBsZWFzdCAxIGdlbmUgcGVyIGNlbGwgYmVjYXVzZSBvdGhlcndpc2UgdGhpcyBjYXVzZXMgcHJvYmxlbXMgZG93bnN0cmVhbQoKIyMgYWRkIGV4cGVyaW1lbnQgY29sdW1uIHRvIG1ldGEgZGF0YToKc3MyX211dGFudHNAbWV0YS5kYXRhJGV4cGVyaW1lbnQgPC0gInNzMl9tdXRhbnRzIgoKIyMgaW5zcGVjdCBvYmplY3QKc3MyX211dGFudHMKYGBgCgpgYGB7ciBub24gZGV0ZWN0ZWQgZ2VuZXN9CiMjIGhvdyBtYW55IGdlbmVzIGFyZSBub3QgZGV0ZWN0ZWQgYXQgYWxsPwpwYXN0ZShsZW5ndGgod2hpY2gocm93U3Vtcyhhcy5tYXRyaXgoc3MyX211dGFudHNAYXNzYXlzJFJOQUBjb3VudHMpKSA9PSAwKSksICJnZW5lcyBhcmUgbm90IGRldGVjdGVkIGluIGFueSBjZWxsIikKYGBgCgpgYGB7ciB6ZXJvIGNvdW50IGNlbGxzLCBlY2hvID0gRkFMU0V9CnBhc3RlKGxlbmd0aChjb2xuYW1lcyhjb3VudHMpKSAtIGxlbmd0aChjb2xuYW1lcyhhcy5tYXRyaXgoc3MyX211dGFudHNAYXNzYXlzJFJOQUBjb3VudHMpKSksICJjZWxscyBoYXZlIHplcm8gY291bnRzIikKYGBgCgojIyMgRmlsdGVyZWQgQ2VsbHMgUGxhdGUgSGVhdG1hcAoKc2V0IHVwIGRhdGEKYGBge3IgcGxhdGVtYXAgc2V0dXB9CiMjIG1ha2UgZGF0YWZyYW1lCmRmX3BsYXRlbWFwIDwtIGRhdGEuZnJhbWUod2VsbF9uYW1lID0gcGhlbm8kd2VsbF9uYW1lX1IsIGNlbGxfbmFtZSA9IHJvd25hbWVzKHBoZW5vKSwgcm93Lm5hbWVzID0gcm93bmFtZXMocGhlbm8pKQoKIyMgZ2V0IGNlbGxzIHRoYXQgYXJlIGZpbHRlcmVkIG91dApjZWxsc19rZXB0IDwtIHdoaWNoKHJvd25hbWVzKGRmX3BsYXRlbWFwKSAlaW4lIHJvd25hbWVzKHNzMl9tdXRhbnRzQG1ldGEuZGF0YSkpCgojIyBtYWtlIGV4dHJhIGNvbHVtbiBpbiBwbG90dGluZyBkZgpkZl9wbGF0ZW1hcCRjb2xvdXIgPC0gImZpbHRlcmVkX291dCIKZGZfcGxhdGVtYXAkY29sb3VyW2NlbGxzX2tlcHRdIDwtICJwYXNzZWRfUUMiCgojIyBpbnNwZWN0CiNoZWFkKGRmX3BsYXRlbWFwKQoKIyNNYWtlIGEgdGFibGUgZm9yIGVhY2gKCiMjbWFrZSBhIG5ldyBkYXRhZnJhbWUgZm9yIHBsb3R0aW5nCnRhYmxlX3BsYXRlbWFwIDwtIGFzLmRhdGEuZnJhbWUodGFibGUoZGZfcGxhdGVtYXAkd2VsbF9uYW1lLCBkZl9wbGF0ZW1hcCRjb2xvdXIpKQoKIyMgbW9kaWZ5IG5hbWVzIG9mIGRhdGFmcmFtZQpuYW1lcyh0YWJsZV9wbGF0ZW1hcCkgPC0gYygid2VsbCIsICJmaWx0ZXJlZCIsICJmcmVxdWVuY3kiKQoKI21ha2Ugc2VwYXJhdGUgZGZzCmRmXzEgPC0gdGFibGVfcGxhdGVtYXBbdGFibGVfcGxhdGVtYXAkZmlsdGVyZWQgPT0gImZpbHRlcmVkX291dCIsXQpkZl8yIDwtIHRhYmxlX3BsYXRlbWFwW3RhYmxlX3BsYXRlbWFwJGZpbHRlcmVkID09ICJwYXNzZWRfUUMiLF0KCiMgbWVyZ2UgdGhlbSBiYWNrIHRvZ2V0aGVyCnRhYmxlX3BsYXRlbWFwIDwtIG1lcmdlKGRmXzEsIGRmXzIsIGJ5ID0gIndlbGwiLCBhbGwgPSBUUlVFKQoKIyMgcmVtb3ZlIHRoZSBpcnJlbGV2YW50IHJvd3MgYW5kIHJlbmFtZSBjb2xzIGFuZCByZW5hbWUgcm93cwp0YWJsZV9wbGF0ZW1hcCA8LSB0YWJsZV9wbGF0ZW1hcFsgLGMoMSwzLDUpXQpuYW1lcyh0YWJsZV9wbGF0ZW1hcCkgPC0gYygid2VsbCIsICJmaWx0ZXJlZF9vdXQiLCAicGFzc2VkX1FDIikKdGFibGVfcGxhdGVtYXAkd2VsbF9uYW1lIDwtIHJvd25hbWVzKHRhYmxlX3BsYXRlbWFwKQoKIyMgYWRkIEExPwojdGFibGVfcGxhdGVtYXBbOTYsXSA8LSBjKCJBMSIsICIwIiwgIjAiKQoKIyMgYWRkIGNvbHMgZm9yIHBsb3R0aW5nCnRhYmxlX3BsYXRlbWFwJFJvdyA8LSBhcy5udW1lcmljKG1hdGNoKHRvdXBwZXIoc3Vic3RyKHRhYmxlX3BsYXRlbWFwJHdlbGwsIDEsIDEpKSwgTEVUVEVSUykpCnRhYmxlX3BsYXRlbWFwJENvbHVtbiA8LSBhcy5udW1lcmljKHN1YnN0cih0YWJsZV9wbGF0ZW1hcCR3ZWxsLCAyLCA1KSkKCiMjIGNhbGN1bGF0ZSBhIHBlcmNlbnRhZ2UKdGFibGVfcGxhdGVtYXAkZmlsdGVyZWRfcGMgPC0gKCh0YWJsZV9wbGF0ZW1hcCRmaWx0ZXJlZF9vdXQpLyh0YWJsZV9wbGF0ZW1hcCRmaWx0ZXJlZF9vdXQgKyB0YWJsZV9wbGF0ZW1hcCRwYXNzZWRfUUMpKSoxMDAKCiMjIGR1ZSB0byBhbiBlcnJvciBpbiB0aGUgc2NhbGVfeV9yZXZlcnNlLCB5b3UgbmVlZCB0byBtYWtlIGEgY29sdW1uIG9mICdyZXZlcnNlZCcgcm93IHZhbHVlcyB0byBwbG90CmZvcihpIGluIHNlcSgxLDgpKXsKICB0YWJsZV9wbGF0ZW1hcCRSb3dfcmV2W3RhYmxlX3BsYXRlbWFwJFJvdyA9PSBpXSA8LSBzZXEoOCwxKVtpXQp9CgojIyBmaW5kIHdlbGxzIHdoZXJlIGl0J3MgemVybwp6ZXJvX3dlbGxzIDwtIHRhYmxlX3BsYXRlbWFwJGZpbHRlcmVkX3BjID09IDAKdGFibGVfcGxhdGVtYXAkZmlsdGVyZWRfcGNbemVyb193ZWxsc10gPC0gTkEKYGBgCgpQbG90CmBgYHtyIHBsYXRlbWFwIHBsb3R9CiMjIHBsb3QKc2FtcGxlX21hcF9ub19yZWFkcyA8LSBnZ3Bsb3QoZGF0YT10YWJsZV9wbGF0ZW1hcCwgYWVzKHg9Q29sdW1uLCB5PVJvd19yZXYpKSArCiAgI3NldCB1cCB0aGUgcGxhdGVtYXAgbGF5b3V0CiAgICBnZW9tX3BvaW50KGRhdGE9ZXhwYW5kLmdyaWQoc2VxKDEsMTIpLCBzZXEoMSw4KSksIGFlcyh4PVZhcjEsIHk9VmFyMiksIGNvbG9yPSJncmV5OTAiLCBmaWxsPSJ3aGl0ZSIsIHNoYXBlPTIxLCBzaXplPTgpICsKICAjQ2hhbmdlIHRoZSBzaGFwZSBhbmQgY29sb3VyIG9mIHBvaW50cyBmb3IgYSB2YXJpYWJsZQogICAgZ2VvbV9wb2ludChhZXMoY29sb3VyID0gZmlsdGVyZWRfcGMpLCBzaXplID0gNykgKwogICNjaGFuZ2UgdGhlIGNvbG91cnMKICAgIHNjYWxlX2NvbG91cl92aXJpZGlzX2MoZ3VpZGUgPSAiY29sb3VyYmFyIiwgbmEudmFsdWU9IndoaXRlIikgKwogICNmaXggdGhlIHJhdGlvIG9mIGNvb3JkaW5hdGVzCiAgICBjb29yZF9maXhlZChyYXRpbz0oMTMvMTIpLyg5LzgpLCB4bGltPWMoMC41LCAxMi41KSwgeWxpbT1jKDAuNiwgOC40KSkgKwogICMgbWFrZSBpbnRvIGEgcGxhdGUgcGxvdAogICAgdGhlbWVfYmRjX21pY3JvdGl0ZXIoKSArCiAgI2FkZCBsYWJlbHMgZm9yIHRoZSB5IGF4aXMKICAgIHNjYWxlX3lfY29udGludW91cyhicmVha3MgPSBzZXEoMSwgOCksIGxhYmVscyA9IExFVFRFUlNbODoxXSkgKwogICNhZGQgbGFiZWxzIGZvciB0aGUgeCBheGlzCiAgICBzY2FsZV94X2NvbnRpbnVvdXMocG9zaXRpb24gPSAidG9wIiwgYnJlYWtzPXNlcSgxLCAxMikpICsKICAjQWRkIGEgdGl0bGUgYW5kIGNoYW5nZSBsYWJlbCBvZiBmaWxsCiAgICBsYWJzKHRpdGxlPSJUaGUgcG9zaXRpb24gb2YgY2VsbHMgd2l0aCB6ZXJvIGNvdW50cyIgLCBzaXplID0gNiwgY29sb3VyID0gInBlcmNlbnRhZ2Ugb2YgY2VsbHMgaW4gdGhpcyB3ZWxsIHdpdGggemVybyBjb3VudHMiKSArCiAgI0ltcHJvdmUgYWVzIG9mIGd1aWRlcwogICAgZ3VpZGVzKGNvbG91ciA9IGd1aWRlX2NvbG9yYmFyKGJhcndpZHRoID0gNCwgYmFyaGVpZ2h0ID0gMSwgdGl0bGU9InBlcmNlbnRhZ2Ugb2YgY2VsbHMgaW4gdGhpcyB3ZWxsIHdpdGggemVybyBjb3VudHMiKSkgKwojIGRpc3BsYXkgbGVnZW5kIG9uIGJvdHRvbSBhbmQgbWFrZSB0ZXh0IGJpZ2dlcgogICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJib3R0b20iLCBsZWdlbmQudGV4dD1lbGVtZW50X3RleHQoc2l6ZT0xMCksIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTApKQoKIyMgcHJpbnQKc2FtcGxlX21hcF9ub19yZWFkcwoKIyMgc2F2ZQpnZ3NhdmUoIi9Vc2Vycy9BbmR5L0dDU0tPL0dDU0tPX2FuYWx5c2lzX2dpdC9pbWFnZXNfdG9fZXhwb3J0L1FDX1NTMl9wbGF0ZW1hcF9ub19jb3VudC5wbmciLCBwbG90ID0gc2FtcGxlX21hcF9ub19yZWFkcywgZGV2aWNlID0gInBuZyIsIHBhdGggPSBOVUxMLCBzY2FsZSA9IDEsIHdpZHRoID0gMTIsIGhlaWdodCA9IDEyLCB1bml0cyA9ICJjbSIsIGRwaSA9IDMwMCwgbGltaXRzaXplID0gVFJVRSkKYGBgCgojIyMgRmlsdGVyIE1pdG9jaG9uZHJpYWwKCk1pdG9jaG9uZHJpYWwgY2VsbCBjb3VudHMKYGBge3IgbWl0byBzZXR1cH0KIyMgb2xkIG1ldGhvZAojIyBUaGlzIG9sZCBtZXRob2QganVzdCBwaWNrZWQgb3V0IHJSTkEgZ2VuZXMgYXMgYSByb3VnaCBlc3RpbWF0ZSwgdGhlIG1ldGhvZCBiZWxvdyBwaWNrcyBvdXQgYWxsIGdlbmVzIGV4cHJlc3NlZCBmcm9tIHRoZSBtaXRjaG9uZHJpYWwgZ2Vub21lCgojIyBleHRyYWN0IG1pdG9jaG9uZHJpYWwgZ2VuZXMgCiNtaXRvX2dlbmVzIDwtIGd0Zlt3aGljaChndGYkVjMgPT0gInJSTkEiKSxdJFY5CiNtaXRvX2dlbmVzIDwtIGdzdWIoIjsuKiIsIiIsIGdzdWIoImdlbmVfaWQgIiwgIiIsIG1pdG9fZ2VuZXMpKQojcGFzdGUoIlRoZXNlIGFyZSB0aGUgbWl0b2Nob25kcmlhbCBnZW5lcyIpCiNoZWFkKG1pdG9fZ2VuZXMpCgojIyBtYWtlIGEgcGVyY2VudGFnZSBtaXRvY29uZHJpYWwgZm9yIGVhY2ggY2VsbCAodGhpcyB3aWxsIHdvcmsgYXMgbG9uZyBhcyB5b3UgZmlsdGVyIGNlbGxzIG91dCB3aXRoIHplcm8gY291bnRzKQojc3MyX211dGFudHMgPC0gUGVyY2VudGFnZUZlYXR1cmVTZXQoc3MyX211dGFudHMsIGZlYXR1cmVzID0gd2hpY2gocm93bmFtZXMoY291bnRzKSAlaW4lIG1pdG9fZ2VuZXMpLCBjb2wubmFtZSA9ICJwZXJjZW50Lm10IikKYGBgCgpgYGB7ciBtaXRvIHNldHVwIG5ldywgZmlnLmhlaWdodCA9IDE1LCBmaWcud2lkdGggPSA2fQojIyBleHRyYWN0IG1pdG8gZ2VuZXMKbWl0b19nZW5lcyA8LSBzczJfbXV0YW50c0Bhc3NheXMkUk5BQGNvdW50c0BEaW1uYW1lc1tbMV1dW2dyZXAoIl5QQkFOS0EtTUlUIixzczJfbXV0YW50c0Bhc3NheXMkUk5BQGNvdW50c0BEaW1uYW1lc1tbMV1dKV0KCiMjIHBsb3QgdGhlIGdlbmVzIGluZGl2aWR1YWxseQpWbG5QbG90KG9iamVjdCA9IHNzMl9tdXRhbnRzLCBmZWF0dXJlcyA9IG1pdG9fZ2VuZXMsIHB0LnNpemUgPSAwLjAxLCBncm91cC5ieSA9ICJleHBlcmltZW50IikKCiMjIG1ha2UgYSBwZXJjZW50YWdlIG1pdG9jb25kcmlhbCBmb3IgZWFjaCBjZWxsICh0aGlzIHdpbGwgd29yayBhcyBsb25nIGFzIHlvdSBmaWx0ZXIgY2VsbHMgb3V0IHdpdGggemVybyBjb3VudHMpCnNzMl9tdXRhbnRzIDwtIFBlcmNlbnRhZ2VGZWF0dXJlU2V0KHNzMl9tdXRhbnRzLCBwYXR0ZXJuID0gIl5QQkFOS0EtTUlUIiwgY29sLm5hbWUgPSAicGVyY2VudC5tdCIpCmBgYAoKcGxvdCBwZXJjZW50YWdlIG1pdG9jaG9uZHJpYWwKYGBge3J9CiMjIHBsb3QgZm9yIHBlcmNlbnRhZ2Ugb2YgbWl0b2Nob25kcmlhbCByZWFkcwp2MSA8LSBWbG5QbG90KG9iamVjdCA9IHNzMl9tdXRhbnRzLCBmZWF0dXJlcyA9ICJwZXJjZW50Lm10IiwgZ3JvdXAuYnkgPSAic3ViX2lkZW50aXR5X3VwZGF0ZWQiLCBwdC5zaXplID0gMC4wMSkgKyAKICAjIyBhZGQgYSBsaW5lIHdoZXJlIHdlIHdpbGwgZmlsdGVyIAogIGdlb21faGxpbmUoeWludGVyY2VwdD0yMCkgKwogICMjIHJlbW92ZSBsZWdlbmQKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpICsKICAjIyBjaGFuZ2UgbGFiZWxzCiAgbGFicyh4ID0gIkdlbm90eXBlIiwgeSA9ICIlIE1pdG9jaG9uZHJpYWwgUmVhZHMiKSArCiAgIyMgcmVtb3ZlIHBsb3QgdGl0bGUKICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF9ibGFuaygpKQoKIyMgcGxvdCBmb3IgcGVyY2VudGFnZSBvZiBtaXRvY2hvbmRyaWFsIHJlYWRzCnYyIDwtIFZsblBsb3Qob2JqZWN0ID0gc3MyX211dGFudHMsIGZlYXR1cmVzID0gInBlcmNlbnQubXQiLCBncm91cC5ieSA9ICJleHBlcmltZW50IiwgcHQuc2l6ZSA9IDAuMDEpICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQ9MjApICsKICAjIyByZW1vdmUgbGVnZW5kCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSArCiAgIyMgZnJlbW92ZSBheGlzIGxhYmVscwogIGxhYnMoeD0iIiwgeSA9ICIiKSArCiAgIyMgcmVtb3ZlIGF4aXMgZWxlbWVudHMKICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF9ibGFuaygpLCBheGlzLnRleHQueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRpY2tzLnkgPSBlbGVtZW50X2JsYW5rKCkpICsKICAjIyBjaGFuZ2UgbGFiZWwgb24gYm90dG9tIG9mIHBsb3QKICBzY2FsZV94X2Rpc2NyZXRlKGxhYmVscyA9ICJBbGwgY2VsbHMiKQoKIyMgcGxvdCB0b2dldGhlcgpRQ19taXRvX3Zpb2xpbiA8LSB2MSArIHYyICsgcGxvdF9sYXlvdXQobmNvbCA9IDIsIG5yb3cgPSAxLCB3aWR0aHMgPSBjKDQsIDEpLCBoZWlnaHRzID0gYygyLCAyKSkKCiMjIHByaW50ClFDX21pdG9fdmlvbGluCgojIyBzYXZlCmdnc2F2ZSgiL1VzZXJzL0FuZHkvR0NTS08vR0NTS09fYW5hbHlzaXNfZ2l0L2ltYWdlc190b19leHBvcnQvUUNfU1MyX21pdG9fdmlvbGluLnBuZyIsIHBsb3QgPSBRQ19taXRvX3Zpb2xpbiwgZGV2aWNlID0gInBuZyIsIHBhdGggPSBOVUxMLCBzY2FsZSA9IDEsIHdpZHRoID0gMTUsIGhlaWdodCA9IDEwLCB1bml0cyA9ICJjbSIsIGRwaSA9IDMwMCwgbGltaXRzaXplID0gVFJVRSkKYGBgCgptYWtlIGEgZGF0YWZyYW1lIGZvciBwbG90dGluZwpgYGB7cn0KZGYgPC0gZGF0YS5mcmFtZShuQ291bnQgPSBsb2cxMChzczJfbXV0YW50c0BtZXRhLmRhdGEkbkNvdW50X1JOQSksIG5HZW5lcyA9IHNzMl9tdXRhbnRzQG1ldGEuZGF0YSRuRmVhdHVyZV9STkEsIGlkZW50aXR5ID0gc3MyX211dGFudHNAbWV0YS5kYXRhJGlkZW50aXR5X3VwZGF0ZWQsIGlkZW50aXR5X2dlbmUgPSBzczJfbXV0YW50c0BtZXRhLmRhdGEkaWRlbnRpdHlfZ2VuZV91cGRhdGVkLCBwZXJjZW50X210ID0gc3MyX211dGFudHNAbWV0YS5kYXRhJHBlcmNlbnQubXQpCmBgYAoKV2hlcmUgZG8gbWl0Y2hvbmRyaWFsIHBvb3IgY2VsbHMgbGllPwpgYGB7cn0KIyMgbWFrZSBleHRyYSBjb2wgZm9yIGZpbHRlcmVkIHZhbHVlczoKZmlsdGVyZWRfb3V0X2NlbGxzIDwtIHdoaWNoKGRmJHBlcmNlbnRfbXQgPiAyMCkgCgojIyBwbG90ClFDX21pdG9fZ3JhcGggPC0gZ2dwbG90KGRmLCBhZXMoeCA9IG5Db3VudCwgeSA9IG5HZW5lcykpICsgCiAgZ2VvbV9wb2ludChhbHBoYSA9IDAuNCkgKwogIHNjYWxlX3NpemUocmFuZ2UgPSBjKDAuMSw0KSkgKwogICNnZW9tX3J1ZygpICsgCiAgc2NhbGVfeV9jb250aW51b3VzKG5hbWUgPSAiTnVtYmVyIG9mIERldGVjdGVkIEdlbmVzIikgKyAKICBzY2FsZV94X2NvbnRpbnVvdXMobmFtZSA9ICJsb2cxMChOdW1iZXIgb2YgVG90YWwgQ291bnRzKSIpICsKICBzY2FsZV9jb2xvcl92aXJpZGlzKG9wdGlvbiA9ICJEIikgKwogIHRoZW1lX3B1YnIoKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIpICsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQ9MykgKwogIGdlb21faGxpbmUoeWludGVyY2VwdD0yMjApICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQ9MzMwMCkgKwogICNhbm5vdGF0ZSBzZWxlY3RlZCBwb2ludHMKICBhbm5vdGF0ZSgicG9pbnQiLCBkZiRuQ291bnRbZmlsdGVyZWRfb3V0X2NlbGxzXSwgZGYkbkdlbmVzW2ZpbHRlcmVkX291dF9jZWxsc10sIHNpemUgPSAyLCBjb2xvdXIgPSAib3JhbmdlIikKCiMjIGFkZCB0aGlzIHRvIGdlbW9fcG9pbnQgaWYgbmVlZGVkOiBhZXMoY29sb3VyID0gcGVyY2VudF9tdCwgc2l6ZSA9IHBlcmNlbnRfbXQpCgojIyBwcmludApRQ19taXRvX2dyYXBoCgojIyBzYXZlCmdnc2F2ZSgiL1VzZXJzL0FuZHkvR0NTS08vR0NTS09fYW5hbHlzaXNfZ2l0L2ltYWdlc190b19leHBvcnQvUUNfU1MyX21pdG9fZ3JhcGgucG5nIiwgcGxvdCA9IFFDX21pdG9fZ3JhcGgsIGRldmljZSA9ICJwbmciLCBwYXRoID0gTlVMTCwgc2NhbGUgPSAxLCB3aWR0aCA9IDEwLCBoZWlnaHQgPSAxMCwgdW5pdHMgPSAiY20iLCBkcGkgPSAzMDAsIGxpbWl0c2l6ZSA9IFRSVUUpCmBgYAoKYGBge3IsIGVjaG8gPSBGQUxTRX0KY2VsbHNfd2l0aF9oaWdoX21pdG9fYnV0X25vdF9maWx0ZXJlZCA8LSBsZW5ndGgod2hpY2goZGYkcGVyY2VudF9tdCA+IDIwICYgZGYkbkdlbmVzID4gMjIwICYgZGYkbkdlbmVzIDwgMzMwMCAmIGRmJG5Db3VudCA+IDMpKQpjZWxsc193aXRoX2hpZ2hfbWl0b19hbmRfZmlsdGVyZWQgPC0gbGVuZ3RoKHdoaWNoKGRmJHBlcmNlbnRfbXQgPiAyMCkpIC0gY2VsbHNfd2l0aF9oaWdoX21pdG9fYnV0X25vdF9maWx0ZXJlZAoKcGFzdGUoIlRoZSBuR2VuZSBhbmQgbkNvdW50cyBmaWx0ZXJzIGNhdGNoIG1vc3Qgb2YgdGhlIGhpZ2ggJSBtaXRvIGNlbGxzICgiLCBjZWxsc193aXRoX2hpZ2hfbWl0b19hbmRfZmlsdGVyZWQgLCIpIGJ1dCBpbnRyb2R1Y2luZyBhIGZpbHRlciB3b3VsZCBjYXB0dXJlIGEgZnVydGhlciIsIGNlbGxzX3dpdGhfaGlnaF9taXRvX2J1dF9ub3RfZmlsdGVyZWQpCmBgYAoKCmBgYHtyLCBmaWcuaGVpZ2h0ID0gNCwgZmlnLndpZHRoID0gMTB9CiMjIHBsb3QgMQpwbG90MSA8LSBGZWF0dXJlU2NhdHRlcihzczJfbXV0YW50cywgZmVhdHVyZTEgPSAibkNvdW50X1JOQSIsIGZlYXR1cmUyID0gInBlcmNlbnQubXQiLCBwdC5zaXplID0gMC4wMSwgZ3JvdXAuYnkgPSAiaWRlbnRpdHlfdXBkYXRlZCIpCgojIyBwbG90IDIKcGxvdDIgPC0gRmVhdHVyZVNjYXR0ZXIoc3MyX211dGFudHMsIGZlYXR1cmUxID0gIm5Db3VudF9STkEiLCBmZWF0dXJlMiA9ICJuRmVhdHVyZV9STkEiLCBwdC5zaXplID0gMC4wMSwgZ3JvdXAuYnkgPSAiaWRlbnRpdHlfdXBkYXRlZCIpCgojIyBwbG90IHRvZ2V0aGVyCnBsb3QxICsgcGxvdDIKYGBgCgojIyBGaWx0ZXIgcG9vciBxdWFsaXR5IGNlbGxzCgppbiB0aGUgTUNBIHBhcGVyOgoiQ2VsbHMgd2l0aCBmZXdlciB0aGFuIDEwMDAgZ2VuZXMgcGVyIGNlbGwgYW5kIDI1MDAgcmVhZHMgcGVyIGNlbGwgd2VyZSByZW1vdmVkIGZyb20gdGhlIGxpdmVyLXN0YWdlIHBhcmFzaXRlcywgdHJvcGhvem9pdGVzLCBtYWxlIGFuZCBmZW1hbGUgZ2FtZXRvY3l0ZXMsIG9va2luZXRlcywgb29raW5ldGVzL29vY3lzdHMsIGFuZCBvb2N5c3Qgc3RhZ2VzLiBDZWxscyB3aXRoIGZld2VyIHRoYW4gNTAwIGdlbmVzIHBlciBjZWxsIGFuZCAyNTAwIHJlYWRzIHBlciBjZWxsIHdlcmUgcmVtb3ZlZCBmcm9tIHNjaGl6b250cyBhbmQgaW5qZWN0ZWQgc3Bvcm96b2l0ZXMuIENlbGxzIHdpdGggZmV3ZXIgdGhhbiA0MCBnZW5lcyBwZXIgY2VsbCBhbmQgMTAwMCByZWFkcyBwZXIgY2VsbCB3ZXJlIHJlbW92ZWQgZnJvbSBtZXJvem9pdGVzLCByaW5ncywgYW5kIGdsYW5kIHNwb3Jvem9pdGVzIChmaWcuIFMyIGFuZCB0YWJsZSBTMSkuIEFkZGl0aW9uYWxseSwgd2UgcmVtb3ZlZCBnZW5lcyBmcm9tIGZ1cnRoZXIgYW5hbHlzaXMgdGhhdCB3ZXJlIGRldGVjdGVkIGluIGZld2VyIHRoYW4gdHdvIGNlbGxzIGFjcm9zcyB0aGUgZW50aXJlIGRhdGFzZXQuIFRoZSBmaW5hbCBkYXRhc2V0IGNvbnRhaW5lZCAxNzg3IGhpZ2gtcXVhbGl0eSBzaW5nbGUgY2VsbHMgZnJvbSAxOTgyIHNlcXVlbmNlZCBjZWxscyBhbmQgNTE1NiBnZW5lcyBvdXQgb2YgNTI0NSBnZW5lcyB3aXRoIGFubm90YXRlZCB0cmFuc2NyaXB0cy4iCgpzbyB1c2U6CjEwMDAgcmVhZHMgcGVyIGNlbGwgJiA0MCBnZW5lcyBwZXIgY2VsbCBhcyBhYnNvbHV0ZSBtaW5pbXVtcwoKYGBge3IsIGZpZy5oZWlnaHQgPSA4LCBmaWcud2lkdGggPSA4fQojIyBwbG90IG1haW4gZG90cGxvdApwbG90MSA8LSBnZ3Bsb3QoZGYsIGFlcyh4ID0gbkNvdW50LCB5ID0gbkdlbmVzLCBjb2xvciA9IGlkZW50aXR5KSkgKyAKICBnZW9tX3BvaW50KGFlcyhjb2xvciA9IGlkZW50aXR5KSwgc2l6ZSA9IDAuMSkgKwogIGdlb21fcnVnKCkgKyAKICBzY2FsZV95X2NvbnRpbnVvdXMobmFtZSA9ICJOdW1iZXIgb2YgRGV0ZWN0ZWQgR2VuZXMiKSArIAogIHNjYWxlX3hfY29udGludW91cyhuYW1lID0gImxvZzEwKE51bWJlciBvZiBUb3RhbCBDb3VudHMpIikgKyAKICB0aGVtZV9wdWJyKCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iKSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0PTMpICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQ9MjIwKSArCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0PTMzMDApICsKICAjIyBpbXByb3ZlIGFlc3RoZXRpY3Mgb2YgZ3VpZGUKICBndWlkZXMoY29sb3VyID0gZ3VpZGVfbGVnZW5kKG92ZXJyaWRlLmFlcyA9IGxpc3Qoc2l6ZT00KSksIHRpdGxlPSJHZW5vdHlwZSIpCgojIyBwbG90IGRlbnNpdHkgcGxvdCB4CmRlbnMxIDwtIGdncGxvdChkZiwgYWVzKHggPSBuQ291bnQsIGZpbGwgPSBpZGVudGl0eSkpICsgCiAgZ2VvbV9kZW5zaXR5KGFscGhhID0gMC4yKSArIAogIHRoZW1lX3ZvaWQoKSArIAogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikKCiMjIHBsb3QgZGVuc2l0eSBwbG90IHkKZGVuczIgPC0gZ2dwbG90KGRmLCBhZXMoeCA9IG5HZW5lcywgZmlsbCA9IGlkZW50aXR5KSkgKyAKICBnZW9tX2RlbnNpdHkoYWxwaGEgPSAwLjIpICsgCiAgdGhlbWVfdm9pZCgpICsgCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSArIAogIGNvb3JkX2ZsaXAoKQoKIyMgcGxvdCB0b2dldGhlcgpRQ19jb21wb3NpdGVfcGxvdCA8LSBkZW5zMSArIHBsb3Rfc3BhY2VyKCkgKyBwbG90MSArIGRlbnMyICsgcGxvdF9sYXlvdXQobmNvbCA9IDIsIG5yb3cgPSAyLCB3aWR0aHMgPSBjKDQsIDEpLCBoZWlnaHRzID0gYygxLCA0KSkKCiMjIHByaW50ClFDX2NvbXBvc2l0ZV9wbG90CgojIyBzYXZlCmdnc2F2ZSgiL1VzZXJzL0FuZHkvR0NTS08vR0NTS09fYW5hbHlzaXNfZ2l0L2ltYWdlc190b19leHBvcnQvUUNfU1MyX2NvbXBvc2l0ZV9wbG90LnBuZyIsIHBsb3QgPSBRQ19jb21wb3NpdGVfcGxvdCwgZGV2aWNlID0gInBuZyIsIHBhdGggPSBOVUxMLCBzY2FsZSA9IDEsIHdpZHRoID0gMjAsIGhlaWdodCA9IDIwLCB1bml0cyA9ICJjbSIsIGRwaSA9IDMwMCwgbGltaXRzaXplID0gVFJVRSkKYGBgCgoqKioKIyAzLiBBbmFseXNpcyB7LnRhYnNldH0KCiMjIyBGaW5hbCBmaWx0ZXIKZmlsdGVyIG91dCBjZWxscwpgYGB7cn0KIyMgc3Vic2V0CnNzMl9tdXRhbnRzX2ZpbmFsIDwtIHN1YnNldChzczJfbXV0YW50cywgc3Vic2V0ID0gbkZlYXR1cmVfUk5BID4gMjIwICYgbkZlYXR1cmVfUk5BIDwgMzMwMCAmIHBlcmNlbnQubXQgPCAyMCAmIG5Db3VudF9STkEgPiAxMDAwKQoKIyMgaW5zcGVjdCByZXN1bHRhbnQgb2JqZWN0CnNzMl9tdXRhbnRzX2ZpbmFsCmBgYAoKYGBge3IsIGVjaG8gPSBGQUxTRX0KcGFzdGUobGVuZ3RoKGNvbG5hbWVzKHNzMl9tdXRhbnRzQGFzc2F5cyRSTkFAY291bnRzKSkgLSBsZW5ndGgoY29sbmFtZXMoc3MyX211dGFudHNfZmluYWxAYXNzYXlzJFJOQUBjb3VudHMpKSwgIiBjZWxscyBhcmUgcmVtb3ZlZCBieSB0aGVzZSBmaWx0ZXJzIikKYGBgCgojIyMgUGxhdGVtYXAgaGVhdG1hcCBmb3IgZmFpbGVkIGNlbGxzCgpzZXQgdXAgZGF0YQpgYGB7ciBwbGF0ZW1hcCBzZXR1cCAyfQojIyBtYWtlIGRhdGFmcmFtZQpkZl9wbGF0ZW1hcCA8LSBkYXRhLmZyYW1lKHdlbGxfbmFtZSA9IHBoZW5vJHdlbGxfbmFtZV9SLCBjZWxsX25hbWUgPSByb3duYW1lcyhwaGVubyksIHJvdy5uYW1lcyA9IHJvd25hbWVzKHBoZW5vKSkKCiMjIGdldCBjZWxscyB0aGF0IGFyZSBmaWx0ZXJlZCBvdXQKY2VsbHNfa2VwdCA8LSB3aGljaChyb3duYW1lcyhkZl9wbGF0ZW1hcCkgJWluJSByb3duYW1lcyhzczJfbXV0YW50c19maW5hbEBtZXRhLmRhdGEpKQoKIyMgbWFrZSBleHRyYSBjb2x1bW4gaW4gcGxvdHRpbmcgZGYKZGZfcGxhdGVtYXAkY29sb3VyIDwtICJmaWx0ZXJlZF9vdXQiCmRmX3BsYXRlbWFwJGNvbG91cltjZWxsc19rZXB0XSA8LSAicGFzc2VkX1FDIgoKIyMgaW5zcGVjdApoZWFkKGRmX3BsYXRlbWFwKQoKIyMgbWFrZSBhIG5ldyBkYXRhZnJhbWUgd2l0aCBtZXRyaWNzIG9mIGludGVyZXN0CnRhYmxlX3BsYXRlbWFwIDwtIGFzLmRhdGEuZnJhbWUodGFibGUoZGZfcGxhdGVtYXAkd2VsbF9uYW1lLCBkZl9wbGF0ZW1hcCRjb2xvdXIpKQpuYW1lcyh0YWJsZV9wbGF0ZW1hcCkgPC0gYygid2VsbCIsICJmaWx0ZXJlZCIsICJmcmVxdWVuY3kiKQoKIyBtYWtlIHNlcGFyYXRlIGRmcwpkZl8xIDwtIHRhYmxlX3BsYXRlbWFwW3RhYmxlX3BsYXRlbWFwJGZpbHRlcmVkID09ICJmaWx0ZXJlZF9vdXQiLF0KZGZfMiA8LSB0YWJsZV9wbGF0ZW1hcFt0YWJsZV9wbGF0ZW1hcCRmaWx0ZXJlZCA9PSAicGFzc2VkX1FDIixdCgojIG1lcmdlIHRoZW0gYmFjayB0b2dldGhlcgp0YWJsZV9wbGF0ZW1hcCA8LSBtZXJnZShkZl8xLCBkZl8yLCBieSA9ICJ3ZWxsIiwgYWxsID0gVFJVRSkKCiMjIHJlbW92ZSB0aGUgaXJyZWxldmFudCByb3dzIGFuZCByZW5hbWUgY29scyBhbmQgcmVuYW1lIHJvd3MKdGFibGVfcGxhdGVtYXAgPC0gdGFibGVfcGxhdGVtYXBbICxjKDEsMyw1KV0KbmFtZXModGFibGVfcGxhdGVtYXApIDwtIGMoIndlbGwiLCAiZmlsdGVyZWRfb3V0IiwgInBhc3NlZF9RQyIpCnRhYmxlX3BsYXRlbWFwJHdlbGxfbmFtZSA8LSByb3duYW1lcyh0YWJsZV9wbGF0ZW1hcCkKCiMjIGFkZCBjb2xzIGZvciBwbG90dGluZwp0YWJsZV9wbGF0ZW1hcCRSb3cgPC0gYXMubnVtZXJpYyhtYXRjaCh0b3VwcGVyKHN1YnN0cih0YWJsZV9wbGF0ZW1hcCR3ZWxsLCAxLCAxKSksIExFVFRFUlMpKQp0YWJsZV9wbGF0ZW1hcCRDb2x1bW4gPC0gYXMubnVtZXJpYyhzdWJzdHIodGFibGVfcGxhdGVtYXAkd2VsbCwgMiwgNSkpCgojIyBpbnNwZWN0OgpoZWFkKHRhYmxlX3BsYXRlbWFwKQoKIyMgY2FsY3VsYXRlIHBlcmNlbnRhZ2UKdGFibGVfcGxhdGVtYXAkZmlsdGVyZWRfcGMgPC0gKCh0YWJsZV9wbGF0ZW1hcCRmaWx0ZXJlZF9vdXQpLyh0YWJsZV9wbGF0ZW1hcCRmaWx0ZXJlZF9vdXQgKyB0YWJsZV9wbGF0ZW1hcCRwYXNzZWRfUUMpKSoxMDAKCiMjIGR1ZSB0byBhbiBlcnJvciBpbiB0aGUgc2NhbGVfeV9yZXZlcnNlLCB5b3UgbmVlZCB0byBtYWtlIGEgY29sdW1uIG9mICdyZXZlcnNlZCcgcm93IHZhbHVlcyB0byBwbG90CmZvcihpIGluIHNlcSgxLDgpKXsKICB0YWJsZV9wbGF0ZW1hcCRSb3dfcmV2W3RhYmxlX3BsYXRlbWFwJFJvdyA9PSBpXSA8LSBzZXEoOCwxKVtpXQp9Cgp6ZXJvX3dlbGxzIDwtIHRhYmxlX3BsYXRlbWFwJGZpbHRlcmVkX3BjID09IDAKdGFibGVfcGxhdGVtYXAkZmlsdGVyZWRfcGNbemVyb193ZWxsc10gPC0gTkEKYGBgCgpwbG90CmBgYHtyIHBsYXRlbWFwIHBsb3QgMn0KIyMgcGxvdApwbGF0ZW1hcF9mYWlsZWRfcWMgPC0gZ2dwbG90KGRhdGE9dGFibGVfcGxhdGVtYXAsIGFlcyh4PUNvbHVtbiwgeT1Sb3dfcmV2KSkgKwogICNzZXQgdXAgdGhlIHBsYXRlbWFwIGxheW91dAogICAgZ2VvbV9wb2ludChkYXRhPWV4cGFuZC5ncmlkKHNlcSgxLDEyKSwgc2VxKDEsOCkpLCBhZXMoeD1WYXIxLCB5PVZhcjIpLCBjb2xvcj0iZ3JleTkwIiwgZmlsbD0id2hpdGUiLCBzaGFwZT0yMSwgc2l6ZT04KSArCiAgI0NoYW5nZSB0aGUgc2hhcGUgYW5kIGNvbG91ciBvZiBwb2ludHMgZm9yIGEgdmFyaWFibGUKICAgIGdlb21fcG9pbnQoYWVzKGNvbG91ciA9IGZpbHRlcmVkX3BjKSwgc2l6ZSA9IDcpICsKICAjY2hhbmdlIHRoZSBjb2xvdXJzCiAgICBzY2FsZV9jb2xvdXJfdmlyaWRpc19jKGd1aWRlID0gImNvbG91cmJhciIsIG5hLnZhbHVlPSJ3aGl0ZSIpICsKICAjQWRkIGEgdGl0bGUgYW5kIGNoYW5nZSBsYWJlbCBvZiBmaWxsCiAgICBsYWJzKHRpdGxlPSJUaGUgcG9zaXRpb24gb2YgY2VsbHMgdGhhdCBmYWlsZWQgUUMiLCBzaXplID0gNikgKwogICNmaXggdGhlIHJhdGlvIG9mIGNvb3JkaW5hdGVzCiAgICBjb29yZF9maXhlZChyYXRpbz0oMTMvMTIpLyg5LzgpLCB4bGltPWMoMC41LCAxMi41KSwgeWxpbT1jKDAuNiwgOC40KSkgKwogICMgbWFrZSBpbnRvIGEgcGxhdGUgcGxvdAogICAgdGhlbWVfYmRjX21pY3JvdGl0ZXIoKSArCiAgI2FkZCBsYWJlbHMgZm9yIHRoZSB5IGF4aXMKICAgIHNjYWxlX3lfY29udGludW91cyhicmVha3MgPSBzZXEoMSwgOCksIGxhYmVscyA9IExFVFRFUlNbODoxXSkgKwogICNhZGQgbGFiZWxzIGZvciB0aGUgeCBheGlzCiAgICBzY2FsZV94X2NvbnRpbnVvdXMocG9zaXRpb24gPSAidG9wIiwgYnJlYWtzPXNlcSgxLCAxMikpICsKICAjSW1wcm92ZSBhZXMgb2YgZ3VpZGVzCiAgICBndWlkZXMoY29sb3VyID0gZ3VpZGVfY29sb3JiYXIoYmFyd2lkdGggPSA0LCBiYXJoZWlnaHQgPSAxLCB0aXRsZT0icGVyY2VudGFnZSBvZiBjZWxscyBpbiB3ZWxsIHRoYXQgZmFpbGVkIFFDIikpICsKICAjIGRpc3BsYXkgbGVnZW5kIG9uIGJvdHRvbSBhbmQgbWFrZSB0ZXh0IGJpZ2dlcgogICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJib3R0b20iLCBsZWdlbmQudGV4dD1lbGVtZW50X3RleHQoc2l6ZT0xMCksIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gOSkpCgojIyBwcmludApwbGF0ZW1hcF9mYWlsZWRfcWMKCiMjIHNhdmUKZ2dzYXZlKCIvVXNlcnMvQW5keS9HQ1NLTy9HQ1NLT19hbmFseXNpc19naXQvaW1hZ2VzX3RvX2V4cG9ydC9RQ19TUzJfcGxhdGVtYXBfZmFpbGVkLnBuZyIsIHBsb3QgPSBwbGF0ZW1hcF9mYWlsZWRfcWMsIGRldmljZSA9ICJwbmciLCBwYXRoID0gTlVMTCwgc2NhbGUgPSAxLCB3aWR0aCA9IDEwLCBoZWlnaHQgPSAxMCwgdW5pdHMgPSAiY20iLCBkcGkgPSAzMDAsIGxpbWl0c2l6ZSA9IFRSVUUpCmBgYAoKIyMjIGJhciBjaGFydCBvZiBkaXN0YW5jZSBmcm9tIGVkZ2Ugb2YgcGxhdGUKCk1ha2UgYSBiYXIgZ3JhcGggdGhhdCBkZXNjcmliZXMgdGhlIG51bWJlciBvZiBmYWlsZWQgY2VsbHMgYnkgZGlzdGFuY2UgZnJvbSB0aGUgZWRnZSBvZiB0aGUgcGxhdGUKYGBge3IgYmFyIGdyYXBoIHByZXB9CiMjIGdldCBsaXN0cyBvZiBjZWxscyBmb3IgZWFjaCBzcXVhcmUgYXJvdW5kIHRoZSBwbGF0ZQp0b3RhbF8wIDwtIHRhYmxlX3BsYXRlbWFwW3doaWNoKHRhYmxlX3BsYXRlbWFwJFJvdyAlaW4lIGMoMSw4KSB8IHRhYmxlX3BsYXRlbWFwJENvbHVtbiAlaW4lIGMoMSwxMikpLCBdCgp0b3RhbF8xIDwtIHRhYmxlX3BsYXRlbWFwW3doaWNoKHRhYmxlX3BsYXRlbWFwJFJvdyAlaW4lIGMoMiw3KSB8IHRhYmxlX3BsYXRlbWFwJENvbHVtbiAlaW4lIGMoMiwxMSkpLCBdCnRvdGFsXzEgPC0gdG90YWxfMVstd2hpY2godG90YWxfMSR3ZWxsICVpbiUgdG90YWxfMCR3ZWxsKSxdCgp0b3RhbF8yIDwtIHRhYmxlX3BsYXRlbWFwW3doaWNoKHRhYmxlX3BsYXRlbWFwJFJvdyAlaW4lIGMoMyw2KSB8IHRhYmxlX3BsYXRlbWFwJENvbHVtbiAlaW4lIGMoMywxMCkpLCBdCnRvdGFsXzIgPC0gdG90YWxfMlstd2hpY2godG90YWxfMiR3ZWxsICVpbiUgdG90YWxfMCR3ZWxsIHwgdG90YWxfMiR3ZWxsICVpbiUgdG90YWxfMSR3ZWxsKSxdCgp0b3RhbF8zIDwtIHRhYmxlX3BsYXRlbWFwW3doaWNoKHRhYmxlX3BsYXRlbWFwJFJvdyAlaW4lIGMoNCw1KSB8IHRhYmxlX3BsYXRlbWFwJENvbHVtbiAlaW4lIGMoNCw5KSksIF0KdG90YWxfMyA8LSB0b3RhbF8zWy13aGljaCh0b3RhbF8zJHdlbGwgJWluJSB0b3RhbF8wJHdlbGwgfCB0b3RhbF8zJHdlbGwgJWluJSB0b3RhbF8xJHdlbGwgfCB0b3RhbF8zJHdlbGwgJWluJSB0b3RhbF8yJHdlbGwpLF0KCiMjIGNyZWF0ZSBhIGRhdGFmcmFtZSB3aGljaCBjYWxjdWxhdGVzIHRoZSBwZXJjZW50YWdlIGZhaWxlZCBmb3IgZWFjaCBkaXN0YW5jZSBmcm9tIHRoZSBlZGdlCmZyZXF1ZW5jeV9vZl9mYWlsZWRfY2VsbHMgPC0gZGF0YS5mcmFtZShwZXJjZW50YWdlX2ZhaWxlZCA9IAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjKAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN1bSh0b3RhbF8wJGZpbHRlcmVkX291dCkgLyAoc3VtKHRvdGFsXzAkcGFzc2VkX1FDKSArIHN1bSh0b3RhbF8wJGZpbHRlcmVkX291dCkpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN1bSh0b3RhbF8xJGZpbHRlcmVkX291dCkgLyAoc3VtKHRvdGFsXzEkcGFzc2VkX1FDKSArIHN1bSh0b3RhbF8xJGZpbHRlcmVkX291dCkpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN1bSh0b3RhbF8yJGZpbHRlcmVkX291dCkgLyAoc3VtKHRvdGFsXzIkcGFzc2VkX1FDKSArIHN1bSh0b3RhbF8yJGZpbHRlcmVkX291dCkpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN1bSh0b3RhbF8zJGZpbHRlcmVkX291dCkgLyAoc3VtKHRvdGFsXzMkcGFzc2VkX1FDKSArIHN1bSh0b3RhbF8zJGZpbHRlcmVkX291dCkpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICkpCgojIyBuZWF0ZW4gdGhlIGRhdGFmcmFtZQpmcmVxdWVuY3lfb2ZfZmFpbGVkX2NlbGxzJGRpc3RhbmNlX2Zyb21fZWRnZSA8LSBjKDAsMSwyLDMpCmBgYAoKYGBge3IgYmFyIGdyYXBoIHBsb3R9CnBvc2l0aW9uX3FjX2ZhaWwgPC0gZ2dwbG90KGZyZXF1ZW5jeV9vZl9mYWlsZWRfY2VsbHMsIGFlcyh4PWRpc3RhbmNlX2Zyb21fZWRnZSwgeT1wZXJjZW50YWdlX2ZhaWxlZCkpICsKICBnZW9tX2JhcihzdGF0PSJpZGVudGl0eSIsIGZpbGw9ImJsYWNrIikrCiAgdGhlbWVfY2xhc3NpYygpICsKICB0aGVtZShwYW5lbC5ncmlkLm1ham9yLnggPSBlbGVtZW50X2JsYW5rKCksIHBhbmVsLmdyaWQubWlub3IueCA9IGVsZW1lbnRfYmxhbmsoKSwgdGV4dCA9IGVsZW1lbnRfdGV4dChzaXplPTEyKSkgKwogICMjIGNoYW5nZSB0aGUgYXhpcyB0aXRsZXMKICBsYWJzKHk9ICJDZWxscyB0aGF0IGZhaWxlZCBRQyAoJSkiLCB4ID0gIk51bWJlciBvZiB3ZWxscyBmcm9tIHRoZSBlZGdlIG9mIHRoZSBwbGF0ZSIpICsKICAjIyBwcmV2ZW50IHRoZSB0aXRsZSBnb2luZyBvZmYgdGhlIGVkZ2Ugb2YgdGhlIHBsb3QKICBjb29yZF9jYXJ0ZXNpYW4oY2xpcCA9ICdvZmYnKQoKIyMgc2F2ZQpnZ3NhdmUoIi9Vc2Vycy9BbmR5L0dDU0tPL0dDU0tPX2FuYWx5c2lzX2dpdC9pbWFnZXNfdG9fZXhwb3J0L1FDX1NTMl9mYWlsZWRfcG9zaXRpb24ucG5nIiwgcGxvdCA9IHBvc2l0aW9uX3FjX2ZhaWwsIGRldmljZSA9ICJwbmciLCBwYXRoID0gTlVMTCwgc2NhbGUgPSAxLCB3aWR0aCA9IDEwLCBoZWlnaHQgPSAxMCwgdW5pdHMgPSAiY20iLCBkcGkgPSAzMDAsIGxpbWl0c2l6ZSA9IFRSVUUpCgojIyBwbG90CnBvc2l0aW9uX3FjX2ZhaWwKYGBgCgojIyMgTWFwcGluZyBQbG90IChGaWd1cmUgUzZBKQoKcHJlcGFyZQpgYGB7ciBtYXBwaW5nIHBsb3QsIGZpZy53aWR0aCA9IDIyLCBmaWcuaGVpZ2h0ID0gNX0KIyMgbWFrZSBkYXRhZnJhbWUKZGZfbWFwcGluZ19yYXRlc19oaXNhdCA8LSBkYXRhLmZyYW1lKGFsaWdubWVudF9yYXRlID0gcGhlbm8kb3ZlcmFsbF9oaXNhdDJfYWxpZ25tZW50X3JhdGUsIGNlbGxfbmFtZSA9IHJvd25hbWVzKHBoZW5vKSwgcm93Lm5hbWVzID0gcm93bmFtZXMocGhlbm8pKQoKIyMgZ2V0IGNlbGxzIHRoYXQgYXJlIGZpbHRlcmVkIG91dApjZWxsc19maWx0ZXJlZCA8LSB3aGljaChyb3duYW1lcyhkZl9tYXBwaW5nX3JhdGVzX2hpc2F0KSAlaW4lIHJvd25hbWVzKHNzMl9tdXRhbnRzX2ZpbmFsQG1ldGEuZGF0YSkpCgojIyBtYWtlIGV4dHJhIGNvbHVtbiBpbiBwbG90dGluZyBkZgpkZl9tYXBwaW5nX3JhdGVzX2hpc2F0JGNvbG91ciA8LSAiRmFpbGVkIFFDIgpkZl9tYXBwaW5nX3JhdGVzX2hpc2F0JGNvbG91cltjZWxsc19maWx0ZXJlZF0gPC0gIlBhc3NlZCBRQyIKCiMjIHBsb3QKbWFwcGluZ19yYXRlX3Bsb3QgPC0gZ2dwbG90KGRmX21hcHBpbmdfcmF0ZXNfaGlzYXQsIGFlcyh4ID0gcmVvcmRlcihjZWxsX25hbWUsYWxpZ25tZW50X3JhdGUsc3VtKSwgeT1hbGlnbm1lbnRfcmF0ZSwgZmlsbCA9IGNvbG91cikpICsKICBnZW9tX2NvbCgpICsgCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSArCiAgbGFicyh4PSJDZWxscyIsIHkgPSAiT3ZlcmFsbCBBbGlnbm1lbnQgUmF0ZSAoJSkiLCBzaXplID0gMTUsIGZpbGwgPSAiUUMgUmVzdWx0IikgKwogIHRoZW1lX2NsYXNzaWMoKSArCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSwgYXhpcy50ZXh0LnggPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50aWNrcy54ID0gZWxlbWVudF9ibGFuaygpLCB0ZXh0ID0gZWxlbWVudF90ZXh0KHNpemU9MjApKSArCiAgIyMgY2hhbmdlIHRoZSBjb2xvdXJzCiAgIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcz1jKCJyZWQyIiwgImdyZWVuNCIpKQoKIyMgc2F2ZQpnZ3NhdmUoIi9Vc2Vycy9BbmR5L0dDU0tPL0dDU0tPX2FuYWx5c2lzX2dpdC9pbWFnZXNfdG9fZXhwb3J0L1FDX1NTMl9tYXBwaW5nX3JhdGUuZXBzIiwgcGxvdCA9IG1hcHBpbmdfcmF0ZV9wbG90LCBkZXZpY2UgPSAiZXBzIiwgcGF0aCA9IE5VTEwsIHNjYWxlID0gMSwgd2lkdGggPSAyMCwgaGVpZ2h0ID0gMTAsIHVuaXRzID0gImNtIiwgZHBpID0gMzAwLCBsaW1pdHNpemUgPSBUUlVFKQoKIyMgcGxvdAptYXBwaW5nX3JhdGVfcGxvdApgYGAKCiMjIyBSZWNvdmVyeSBwbG90cwoKSG93IG1hbnkgY2VsbHMgYXJlIHJlY292ZXJlZCBwZXIgY29uZGl0aW9uPwpgYGB7cn0KIyMgZXh0cmFjdCBkYXRhCmRmX2NlbGxzX3JlY292ZXJlZCA8LSBhcy5kYXRhLmZyYW1lKHRhYmxlKHNzMl9tdXRhbnRzX2ZpbmFsQG1ldGEuZGF0YSRzdWJfaWRlbnRpdHlfdXBkYXRlZCkpCmRmX2NlbGxzX3Byb2ZpbGVkIDwtIGFzLmRhdGEuZnJhbWUodGFibGUocGhlbm8kc3ViX2lkZW50aXR5X3VwZGF0ZWQpKQoKIyMgbWFrZSBhIGRmIG9mIHRoZSBtZXRyaWNzCmRmX2NlbGxzX3JlY292ZXJlZCA8LSBtZXJnZShkZl9jZWxsc19yZWNvdmVyZWQsIGRmX2NlbGxzX3Byb2ZpbGVkLCBieSA9ICJWYXIxIikKbmFtZXMoZGZfY2VsbHNfcmVjb3ZlcmVkKSA8LSBjKCJnZW5vdHlwZSIsICJyZWNvdmVyZWQiLCAicHJvZmlsZWQiKQoKIyMgY2FsY3VsYXRlIHBlcmVjZW50YWdlCmRmX2NlbGxzX3JlY292ZXJlZCRyZWNvdmVyZWRfcGMgPC0gKGRmX2NlbGxzX3JlY292ZXJlZCRyZWNvdmVyZWQvZGZfY2VsbHNfcmVjb3ZlcmVkJHByb2ZpbGVkKSoxMDAKCiMjIHJvdW5kIHVwIHBlcmNlbnRhZ2UgZm9yIGxhYmVscwpkZl9jZWxsc19yZWNvdmVyZWQkcmVjb3ZlcmVkX3BjX3JvdW5kZWQgPC0gc2lnbmlmKGRmX2NlbGxzX3JlY292ZXJlZCRyZWNvdmVyZWRfcGMsIDIpCmRmX2NlbGxzX3JlY292ZXJlZCRyZWNvdmVyZWRfcGNfcm91bmRlZCA8LSBwYXN0ZTAoZGZfY2VsbHNfcmVjb3ZlcmVkJHJlY292ZXJlZF9wY19yb3VuZGVkLCAiICUiKQoKIyMgbWFrZSBhIGNvbHVtbiBmb3IgbnVtYmVyIG9mIGNlbGxzIGFubm90YXRpb24KZGZfY2VsbHNfcmVjb3ZlcmVkJG51bWJlcl9jZWxsc19hbm5vdGF0aW9uIDwtIHBhc3RlMCgibiA9ICIsIGRmX2NlbGxzX3JlY292ZXJlZCRyZWNvdmVyZWQpCgojIyBpbnNwZWN0IGRhdGFmcmFtZQpkZl9jZWxsc19yZWNvdmVyZWQKYGBgCgpgYGB7cn0KIyNwbG90ClFDX2J5X2dlbm90eXBlIDwtIGdncGxvdChkZl9jZWxsc19yZWNvdmVyZWQsIGFlcyh4PWdlbm90eXBlLCB5PXJlY292ZXJlZF9wYyAsZmlsbD1nZW5vdHlwZSkpICsgCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIpICsKICB5bGltKDAsIDEwMCkgKwogICNzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlID0gIlNldDEiKSArCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbD1yZWNvdmVyZWRfcGNfcm91bmRlZCwgdmp1c3Q9MC41LCBoanVzdCA9IDEuNSkpICsKICBnZW9tX3RleHQoYWVzKGxhYmVsPW51bWJlcl9jZWxsc19hbm5vdGF0aW9uLCB2anVzdD0wLjUsIGhqdXN0ID0gLTAuMDUpKSArCiAgbGFicyh5ID0gIlBlcmNlbnRhZ2Ugb2YgY2VsbHMgcmVjb3ZlcmVkIiwgeCA9ICJHZW5vdHlwZSIpICsKICBjb29yZF9mbGlwKGNsaXAgPSAib2ZmIikgKwogIHRoZW1lX2NsYXNzaWMoKSArCiAgIyMgcmVtb3ZlIGxlZ2VuZCArIGFkZCBib3JkZXIgc28gaXQgZG9lc24ndCBjbGlwIHRoZSBhbm5vdGF0aW9uIAogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0ibm9uZSIsIHBsb3QubWFyZ2luID0gdW5pdChjKDEsMywxLDMpLCAibGluZXMiKSkKCiMjIHBsb3QKUUNfYnlfZ2Vub3R5cGUKCiMjIHNhdmUKZ2dzYXZlKCIvVXNlcnMvQW5keS9HQ1NLTy9HQ1NLT19hbmFseXNpc19naXQvaW1hZ2VzX3RvX2V4cG9ydC9RQ19TUzJfYnlfZ2Vub3R5cGUucG5nIiwgcGxvdCA9IFFDX2J5X2dlbm90eXBlLCBkZXZpY2UgPSAicG5nIiwgcGF0aCA9IE5VTEwsIHNjYWxlID0gMSwgd2lkdGggPSAxNSwgaGVpZ2h0ID0gMTAsIHVuaXRzID0gImNtIiwgZHBpID0gMzAwLCBsaW1pdHNpemUgPSBUUlVFKQpgYGAKCkludmVzdGlnYXRlIDIwIGFuZCAyIGZ1cnRoZXIKYGBge3J9CiMjIGhvdyBtYW55IHBsYXRlcz8KcGxhdGVfaW52ZXN0aWdhdGlvbiA8LSBwaGVub1t3aGljaChwaGVubyRzdWJfaWRlbnRpdHlfdXBkYXRlZCA9PSAiR0NTS08tMjAiIHwgcGhlbm8kc3ViX2lkZW50aXR5X3VwZGF0ZWQgPT0gIkdDU0tPLTIiIHwgcGhlbm8kc3ViX2lkZW50aXR5X3VwZGF0ZWQgPT0gIldULTIiIHwgcGhlbm8kc3ViX2lkZW50aXR5X3VwZGF0ZWQgPT0gIldULTIwIiksIF0KdGFibGUocGxhdGVfaW52ZXN0aWdhdGlvbiRwbGF0ZV9pZF91bmlxdWUpCmBgYAoKYWRkIGNvbHVtbnMgaWYgaXQgZmFpbGVkIFFDOgpgYGB7cn0KIyMgZ2V0IGNlbGxzIHRoYXQgYXJlIGZpbHRlcmVkIG91dApjZWxsc19rZXB0IDwtIHdoaWNoKHJvd25hbWVzKHBsYXRlX2ludmVzdGlnYXRpb24pICVpbiUgcm93bmFtZXMoc3MyX211dGFudHNfZmluYWxAbWV0YS5kYXRhKSkKCiMjIG1ha2UgZXh0cmEgY29sdW1uIGluIHBsb3R0aW5nIGRmCnBsYXRlX2ludmVzdGlnYXRpb24kY29sb3VyIDwtICJmaWx0ZXJlZF9vdXQiCnBsYXRlX2ludmVzdGlnYXRpb24kY29sb3VyW2NlbGxzX2tlcHRdIDwtICJwYXNzZWRfUUMiCgp0YWJsZShwbGF0ZV9pbnZlc3RpZ2F0aW9uJGNvbG91cikKYGBgCgpgYGB7cn0KIyMgYWRkIGNvbHMgZm9yIHBsb3R0aW5nCnBsYXRlX2ludmVzdGlnYXRpb24kUm93IDwtIGFzLm51bWVyaWMobWF0Y2godG91cHBlcihzdWJzdHIocGxhdGVfaW52ZXN0aWdhdGlvbiR3ZWxsX25hbWVfUiwgMSwgMSkpLCBMRVRURVJTKSkKcGxhdGVfaW52ZXN0aWdhdGlvbiRDb2x1bW4gPC0gYXMubnVtZXJpYyhzdWJzdHIocGxhdGVfaW52ZXN0aWdhdGlvbiR3ZWxsX25hbWVfUiwgMiwgNSkpCmBgYAoKcGxvdApgYGB7cn0KIyMgZmluZCB1bmlxdWUgcGxhdGUgbmFtZXMKcGxhdGVfbmFtZXMgPC0gdW5pcXVlKHBsYXRlX2ludmVzdGlnYXRpb24kcGxhdGVfaWRfdW5pcXVlKQoKIyMgZHVlIHRvIGFuIGVycm9yIGluIHRoZSBzY2FsZV95X3JldmVyc2UsIHlvdSBuZWVkIHRvIG1ha2UgYSBjb2x1bW4gb2YgJ3JldmVyc2VkJyByb3cgdmFsdWVzIHRvIHBsb3QKZm9yKGkgaW4gc2VxKDEsOCkpewogIHBsYXRlX2ludmVzdGlnYXRpb24kUm93X3JldltwbGF0ZV9pbnZlc3RpZ2F0aW9uJFJvdyA9PSBpXSA8LSBzZXEoOCwxKVtpXQp9CgojIyBtYWtlIGFuIGVtcHR5IGxpc3QKcGxvdF9saXN0ID0gbGlzdCgpCgojIyBydW4gZm9yIGxvb3Agd2hpY2ggd2lsbCBnZW5lcmF0ZSBwbG90cyBmb3IgZWFjaCBwbGF0ZQpmb3IoaSBpbiBzZXFfYWxvbmcocGxhdGVfbmFtZXMpKXsKIyMgbWFrZSBkZgogIHRhYmxlX3BsYXRlbWFwIDwtIHBsYXRlX2ludmVzdGlnYXRpb25bcGxhdGVfaW52ZXN0aWdhdGlvbiRwbGF0ZV9pZF91bmlxdWUgPT0gcGxhdGVfbmFtZXNbaV0sIF0KICAjIyBwbG90CiAgcCA8LSBnZ3Bsb3QoZGF0YT10YWJsZV9wbGF0ZW1hcCwgYWVzKHg9Q29sdW1uLCB5PVJvd19yZXYpKSArCiAgI3NldCB1cCB0aGUgcGxhdGVtYXAgbGF5b3V0CiAgICAgIGdlb21fcG9pbnQoZGF0YT1leHBhbmQuZ3JpZChzZXEoMSwgMTIpLCBzZXEoMSwgOCkpLCBhZXMoeD1WYXIxLCB5PVZhcjIpLCBjb2xvcj0iZ3JleTkwIiwgZmlsbD0id2hpdGUiLCBzaGFwZT0yMSwgc2l6ZT04KSArCiAgI0NoYW5nZSB0aGUgc2hhcGUgYW5kIGNvbG91ciBvZiBwb2ludHMgZm9yIGEgdmFyaWFibGUKICAgIGdlb21fcG9pbnQoYWVzKGNvbG91ciA9IGNvbG91ciksIHNpemUgPSA3KSArCiAgI2NoYW5nZSB0aGUgY29sb3VycwogICAgI3NjYWxlX2NvbG91cl92aXJpZGlzX2MoZ3VpZGUgPSAiY29sb3VyYmFyIiwgbmEudmFsdWU9IndoaXRlIikgKwogICMgbWFrZSBpbnRvIGEgcGxhdGUgcGxvdAogICAgdGhlbWVfYmRjX21pY3JvdGl0ZXIoKSArCiAgI2ZpeCB0aGUgcmF0aW8gb2YgY29vcmRpbmF0ZXMKICAgIGNvb3JkX2ZpeGVkKHJhdGlvPSgxMy8xMikvKDkvOCksIHhsaW09YygwLjUsIDEyLjUpLCB5bGltPWMoMC42LCA4LjQpKSArCiAgI2FkZCBsYWJlbHMgZm9yIHRoZSB5IGF4aXMKICAgIHNjYWxlX3lfY29udGludW91cyhicmVha3M9c2VxKDEsIDgpLCBsYWJlbHM9TEVUVEVSU1s4OjFdKSArCiAgI2FkZCBsYWJlbHMgZm9yIHRoZSB4IGF4aXMKICAgIHNjYWxlX3hfY29udGludW91cyhwb3NpdGlvbiA9ICJ0b3AiLCBicmVha3M9c2VxKDEsIDEyKSkgKwogICNBZGQgYSB0aXRsZQogICAgbGFicyh0aXRsZT1wbGF0ZV9uYW1lc1tpXSAsIHNpemUgPSA2LCBjb2xvdXIgPSAiUUMgUmVzdWx0IikgKwogICNyb3RhdGUgbGVnZW5kIGd1aWRlIGJlY2F1c2Ugb3RoZXJ3aXNlIHlvdSBjYW4ndCBzZWUgbnVtYmVyczoKICAgIGd1aWRlcyhmaWxsID0gZ3VpZGVfY29sb3JiYXIoYmFyd2lkdGggPSAwLjUsIGJhcmhlaWdodCA9IDEwLCB0aXRsZT0iVmFsdWUiKSwgY29sb3VyID0gZ3VpZGVfbGVnZW5kKG92ZXJyaWRlLmFlcyA9IGxpc3Qoc2l6ZT00KSkpICsKICAjY2hhbmdlIHRoZSBjb2xvdXJzCiAgIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzPWMoInJlZDIiLCAiZ3JlZW40IikpICsKICAjIG1ha2UgbWltbmltdW0gcG9pbnQgc2l6ZSBiaWdnZXIKICAgICNzY2FsZV9zaXplX2NvbnRpbnVvdXMocmFuZ2UgPSBjKDIsMTApKSArCiAgIyBtYWtlIHRoZSBmb250IHNpemUgaW4gdGhlIGxlZ2VuZCBiaWdnZXIKICAgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0iYm90dG9tIiwgbGVnZW5kLnRleHQ9ZWxlbWVudF90ZXh0KHNpemU9MTAsIGNvbG91ciA9ICJibGFjayIpLCBsZWdlbmQudGl0bGU9ZWxlbWVudF90ZXh0KHNpemU9MTApKQogIAojIyBwcmludApwbG90X2xpc3RbW2ldXSA8LSBwCn0KCmZvciAoaSBpbiBzZXFfYWxvbmcocGxhdGVfbmFtZXMpKSB7CiAgICBwcmludChwbG90X2xpc3RbW2ldXSkKfQpgYGAKCmBgYHtyfQojIyBsb2FkIHRoaXMgbGlicmFyeSB0byB1c2UgZ3JpZC5hcnJhbmdlIGZ1bmN0aW9uCmxpYnJhcnkoZ3JpZEV4dHJhKQoKIyMgdXNlIHRoaXMgZnVuY3Rpb24gdG8gZXh0cmFjdCBsZWdlbmQ6CiMjIHNvdXJjZTogaHR0cHM6Ly9zdGFja292ZXJmbG93LmNvbS9xdWVzdGlvbnMvMTM2NDk0NzMvYWRkLWEtY29tbW9uLWxlZ2VuZC1mb3ItY29tYmluZWQtZ2dwbG90cwojIyBzb3VyY2U6IGh0dHBzOi8vZ2l0aHViLmNvbS9oYWRsZXkvZ2dwbG90Mi93aWtpL1NoYXJlLWEtbGVnZW5kLWJldHdlZW4tdHdvLWdncGxvdDItZ3JhcGhzCmdfbGVnZW5kPC1mdW5jdGlvbihhLmdwbG90KXsKICAgdG1wIDwtIGdncGxvdF9ndGFibGUoZ2dwbG90X2J1aWxkKGEuZ3Bsb3QpKQogICBsZWcgPC0gd2hpY2goc2FwcGx5KHRtcCRncm9icywgZnVuY3Rpb24oeCkgeCRuYW1lKSA9PSAiZ3VpZGUtYm94IikKICAgbGVnZW5kIDwtIHRtcCRncm9ic1tbbGVnXV0KICAgcmV0dXJuKGxlZ2VuZCl9CgojIyBnZXQgbGVnZW5kCm15bGVnZW5kPC1nX2xlZ2VuZChwbG90X2xpc3RbWzFdXSkKCiMjIG1ha2UgYSBmaW5hbCBwbG90ClFDX2ZhaWxlZF9wbGF0ZXMgPC0gZ3JpZC5hcnJhbmdlKGFycmFuZ2VHcm9iKHBsb3RfbGlzdFtbMV1dICsgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJub25lIikgKyBsYWJzKHRpdGxlID0gcGFzdGUoIk11dGFudCAyMCIsICJcbiIsICJwbGF0ZSAxIikpICsgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSkpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGxvdF9saXN0W1syXV0gKyB0aGVtZShsZWdlbmQucG9zaXRpb249Im5vbmUiKSArIGxhYnModGl0bGUgPSBwYXN0ZSgiTXV0YW50IDIwIiwgIlxuIiwgInBsYXRlIDIiKSkgKyB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwbG90X2xpc3RbWzNdXSArIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0ibm9uZSIpICsgbGFicyh0aXRsZSA9IHBhc3RlKCJNdXRhbnQgMjAiLCAiXG4iLCAicGxhdGUgMyIpKSArIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBsb3RfbGlzdFtbNF1dICsgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJub25lIikgKyBsYWJzKHRpdGxlID0gcGFzdGUoIk11dGFudCAyMCIsICJcbiIsICJwbGF0ZSA0IikpICsgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSkpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGxvdF9saXN0W1s1XV0gKyB0aGVtZShsZWdlbmQucG9zaXRpb249Im5vbmUiKSArIGxhYnModGl0bGUgPSBwYXN0ZSgiTXV0YW50IDIiLCAiXG4iLCAicGxhdGUgMSIpKSArIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBsb3RfbGlzdFtbNl1dICsgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJub25lIikgKyBsYWJzKHRpdGxlID0gcGFzdGUoIk11dGFudCAyIiwgIlxuIiwgInBsYXRlIDIiKSkgKyB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSksIG5yb3c9MiksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBteWxlZ2VuZCwgbnJvdz0yLGhlaWdodHM9YygxMCwyKSkKCiMjIHBsb3QKUUNfZmFpbGVkX3BsYXRlcwoKIyMgc2F2ZQpnZ3NhdmUoIi9Vc2Vycy9BbmR5L0dDU0tPL0dDU0tPX2FuYWx5c2lzX2dpdC9pbWFnZXNfdG9fZXhwb3J0L1FDX1NTMl9mYWlsZWRfcGxhdGVzLnBuZyIsIHBsb3QgPSBRQ19mYWlsZWRfcGxhdGVzLCBkZXZpY2UgPSAicG5nIiwgcGF0aCA9IE5VTEwsIHNjYWxlID0gMSwgd2lkdGggPSAyNywgaGVpZ2h0ID0gMjUsIHVuaXRzID0gImNtIiwgZHBpID0gMzAwLCBsaW1pdHNpemUgPSBUUlVFKQpgYGAKCiMjIyBBZGQgYnVsayBtZXRhZGF0YQoKQWRkIGluIGJ1bGsgZGF0YSBwcmVkaWN0aW9ucwoKIyMjIyBob28gZXQgYWwuCmBgYHtyIGhvb30KI1BiIFByZWRpY3Rpb24gY29ycmVsYXRpb25zIHdpdGggYnVsayBkYXRhIChhc2V4dWFsIGhvbyk6IAoKI0xvYWQgaW4gcmVxdWlyZWQgcGFja2FnZToKbGlicmFyeShIbWlzYykKI0Nvb2VyY2UgZXhwcmVzc2lvbiBkYXRhIGludG8gYSBtYXRyaXggYW5kIGxvYWQgaW4gdGhlIHJlZmVyZW5jZSB0aW1lY291cnNlIGRhdGE6CngxMCA8LSBhcy5tYXRyaXgoc3MyX211dGFudHNfZmluYWxAYXNzYXlzJFJOQUBkYXRhKQpyb3duYW1lcyh4MTApIDwtIGdzdWIoIi0iLCAiXyIsIHJvd25hbWVzKHgxMCkpCiNyZWFkIGluIGJ1bGsgZGF0YToKaG9vPC1hcy5tYXRyaXgocmVhZC50YWJsZSgiL1VzZXJzL0FuZHkvR0NTS08vR0NTS09fYW5hbHlzaXNfZ2l0L2RhdGEvUmVmZXJlbmNlL2hvb19iZXJnMi50eHQiLGhlYWRlcj1ULCByb3cubmFtZXM9MSkpCiNNYWtlIGEgYmxhbmsgZGF0YWZyYW1lIGluIHdoaWNoIHRvIGFkZCBwcmVkaWN0aW9uOgpkZiA8LSBkYXRhLmZyYW1lKG1hdHJpeChuY29sID0gNCwgbnJvdyA9IDApKQpjb2xuYW1lcyhkZikgPC0gYygiUHJlZGljdGlvbihTcGVhcm1hbikiLCJyKFNwZWFybWFuKSIsIlByZWRpY3Rpb24oUGVhcnNvbnMpIiwicihQZWFyc29ucykiKQojRG8gY29ycmVsYXRpb25zIHdpdGggYnVsayBkYXRhIHVzaW5nIGJvdGggU3BlYXJtYW4gYW5kIFBlYXJzb24gKGFuZCB0aGUgdG9wIDEwMDAgZ2VuZXMpOgpmb3IgKGkgaW4gMTpuY29sKHgxMCkpCnsKICBzaGFyZWQ8LWludGVyc2VjdChyb3cubmFtZXMoYXMubWF0cml4KGhlYWQoc29ydCh4MTBbLGldLCBkZWNyZWFzaW5nPVRSVUUpLDEwMDApKSkscm93Lm5hbWVzKGhvbykpCiAgc3RlcDA8LXJjb3JyKHgxMFtzaGFyZWQsaV0saG9vW3NoYXJlZCwxOjEyXSx0eXBlID0gInNwZWFybWFuIikKICBzdGVwMTwtYXMubWF0cml4KHQoc3RlcDAkclsyOjEzLDFdKSkKICBzdGVwMjwtcmNvcnIoeDEwW3NoYXJlZCxpXSxob29bc2hhcmVkLDE6MTJdLHR5cGUgPSAicGVhcnNvbiIpCiAgc3RlcDM8LWFzLm1hdHJpeCh0KHN0ZXAyJHJbMjoxMywxXSkpCiAgc3RlcDQ8LWNiaW5kKGNvbG5hbWVzKHN0ZXAxKVt3aGljaC5tYXgoc3RlcDEpXSxzdGVwMVt3aGljaC5tYXgoc3RlcDEpXSxjb2xuYW1lcyhzdGVwMylbd2hpY2gubWF4KHN0ZXAzKV0sc3RlcDNbd2hpY2gubWF4KHN0ZXAzKV0pCiAgY29sbmFtZXMoc3RlcDQpIDwtIGMoIlByZWRpY3Rpb24oU3BlYXJtYW4pIiwicihTcGVhcm1hbikiLCJQcmVkaWN0aW9uKFBlYXJzb25zKSIsInIoUGVhcnNvbnMpIikKICByb3duYW1lcyhzdGVwNCk8LWNvbG5hbWVzKHgxMClbaV0KICBkZjwtcmJpbmQoZGYsc3RlcDQpCn0KI1dyaXRlIG91dCBkYXRhIGludG8gYSBjc3YgZmlsZToKI3dyaXRlLmNzdihkZnJpbmdyLGZpbGU9Ii9Vc2Vycy9hcjE5L0Rlc2t0b3AvUGhEL0FSMDRfR0NTS09fcHJvamVjdC9BbGxfbXV0YW50c19GZWJfMjAxOC9wcmVkaWN0aW9ucGJjb21iaW5lZC5jc3YiKQojQ2hhbmdlIHRoZSBmb3JtYXQgb2YgdGhlIG91dHB1dCB0byBtYWtlIGl0IG1vcmUgcmVhZGFibGU6CiNnc3ViKCJQYl8iLCIiLCBkZnJpbmdyWywxXSkgLSBNYWtlIHByZWRpY3Rpb25zIGludG8gMThoci5kYXQgZm9ybWF0OgoKI3NwZWFybWFuOgpkZlssMV0gPC0gZ3N1YigiUGJfIiwiIiwgZGZbLDFdKQojUmVtb3ZlIGhyLmRhdCBmcm9tIGxpc3Q6CmRmWywxXSA8LSBnc3ViKCJoci5kYXQiLCIiLCBkZlssMV0pCiNDaGVjayAtIGRmcmluZ3JbLDFdCiNNYWtlIGludG8gYSBudW1iZXI6CmRmWywxXSA8LSBhcy5udW1lcmljKGRmWywxXSkKZGZbLDJdIDwtIGFzLm51bWVyaWMoYXMuY2hhcmFjdGVyKGRmWywyXSkpCgojcGVhcnNvbjoKZGZbLDNdIDwtIGdzdWIoIlBiXyIsIiIsIGRmWywzXSkKI1JlbW92ZSBoci5kYXQgZnJvbSBsaXN0OgpkZlssM10gPC0gZ3N1YigiaHIuZGF0IiwiIiwgZGZbLDNdKQojQ2hlY2sgLSBkZnJpbmdyWywxXQojTWFrZSBpbnRvIGEgbnVtYmVyOgpkZlssM10gPC0gYXMubnVtZXJpYyhkZlssM10pCmRmWyw0XSA8LSBhcy5udW1lcmljKGFzLmNoYXJhY3RlcihkZlssNF0pKQojYWRkIHRvIDEwWCBvYmplY3Q6CnNzMl9tdXRhbnRzX2ZpbmFsIDwtIEFkZE1ldGFEYXRhKHNzMl9tdXRhbnRzX2ZpbmFsLCBtZXRhZGF0YSA9IGRmKQpgYGAKCiMjIyMgS2FzaWEncyBkYXRhCkNhbiBhbHNvIGRvIHdpdGggS2FzaWEncyB0aW1lY291cnNlIGRhdGE6CmBgYHtyIGthc2lhfQprYXM8LWFzLm1hdHJpeChyZWFkLnRhYmxlKCIvVXNlcnMvQW5keS9HQ1NLTy9HQ1NLT19hbmFseXNpc19naXQvZGF0YS9SZWZlcmVuY2UvQVAyT0VUQy50eHQiLGhlYWRlcj1ULCByb3cubmFtZXM9MSkpCiNNYWtlIGEgYmxhbmsgZGF0YWZyYW1lIGluIHdoaWNoIHRvIGFkZCBwcmVkaWN0aW9uOgpkZnMgPC0gZGF0YS5mcmFtZShtYXRyaXgobmNvbCA9IDQsIG5yb3cgPSAwKSkKY29sbmFtZXMoZGZzKSA8LSBjKCJJRCIsIlByZWRpY3Rpb24iLCJyIChQZWFyc29uKSIpCiNEbyBjb3JyZWxhdGlvbnMgd2l0aCBidWxrIGRhdGEgdXNpbmcgYm90aCBTcGVhcm1hbiBhbmQgUGVhcnNvbiAoYW5kIHRoZSB0b3AgMTAwMCBnZW5lcyk6CmZvciAoaSBpbiAxOm5jb2woeDEwKSkKewogIHNoYXJlZDwtaW50ZXJzZWN0KHJvdy5uYW1lcyhhcy5tYXRyaXgoaGVhZChzb3J0KHgxMFssaV0sIGRlY3JlYXNpbmc9VFJVRSksMTAwMCkpKSxyb3duYW1lcyhrYXMpKQogIHN0ZXAwPC1yY29ycih4MTBbc2hhcmVkLGldLGthc1tzaGFyZWQsMToxMF0sdHlwZSA9ICJzcGVhcm1hbiIpCiAgc3RlcDE8LWFzLm1hdHJpeCh0KHN0ZXAwJHJbMjoxMSwxXSkpCiAgc3RlcDI8LXJjb3JyKHgxMFtzaGFyZWQsaV0sa2FzW3NoYXJlZCwxOjEwXSx0eXBlID0gInBlYXJzb24iKQogIHN0ZXAzPC1hcy5tYXRyaXgodChzdGVwMiRyWzI6MTEsMV0pKQogIHN0ZXA0PC1jYmluZChjb2xuYW1lcyhzdGVwMSlbd2hpY2gubWF4KHN0ZXAxKV0sc3RlcDFbd2hpY2gubWF4KHN0ZXAxKV0sY29sbmFtZXMoc3RlcDMpW3doaWNoLm1heChzdGVwMyldLHN0ZXAzW3doaWNoLm1heChzdGVwMyldKQogIGNvbG5hbWVzKHN0ZXA0KSA8LSBjKCJQcmVkaWN0aW9uKFNwZWFybWFuKSIsInIoU3BlYXJtYW4pIiwiUHJlZGljdGlvbihQZWFyc29ucykiLCJyKFBlYXJzb25zKSIpCiAgcm93bmFtZXMoc3RlcDQpPC1jb2xuYW1lcyh4MTApW2ldCiAgZGZzPC1yYmluZChkZnMsc3RlcDQpCn0KI1dyaXRlIG91dCBkYXRhIGludG8gYSBjc3YgZmlsZToKI3dyaXRlLmNzdihkZixmaWxlPSIvVXNlcnMvYXIxOS9EZXNrdG9wL1BoRC9BUjA0X0dDU0tPX3Byb2plY3QvQWxsX211dGFudHNfRmViXzIwMTgvcHJlZGljdGlvbmthc2lhY29tYmluZWQuY3N2IikKCiNDaGFuZ2UgdGhlIGZvcm1hdCBvZiB0aGUgb3V0cHV0IHRvIG1ha2UgaXQgbW9yZSByZWFkYWJsZToKI2dzdWIoIlBiXyIsIiIsIGRmc1ssMV0pIC0gTWFrZSBwcmVkaWN0aW9ucyBpbnRvIDE4aHIuZGF0IGZvcm1hdDoKZGZzWywxXSA8LSBnc3ViKCJYIiwiIiwgZGZzWywxXSkKI01ha2UgaW50byBhIG51bWJlcjoKZGZzWywxXSA8LSBhcy5udW1lcmljKGRmc1ssMV0pCiNNYWtlIGludG8gYSBudW1iZXI6CmRmc1ssMl0gPC0gYXMubnVtZXJpYyhhcy5jaGFyYWN0ZXIoZGZzWywyXSkpCgojZ3N1YigiUGJfIiwiIiwgZGZzWywxXSkgLSBNYWtlIHByZWRpY3Rpb25zIGludG8gMThoci5kYXQgZm9ybWF0OgpkZnNbLDNdIDwtIGdzdWIoIlgiLCIiLCBkZnNbLDNdKQojTWFrZSBpbnRvIGEgbnVtYmVyOgpkZnNbLDNdIDwtIGFzLm51bWVyaWMoZGZzWywzXSkKI2Rmc1ssMV0KI01ha2UgaW50byBhIG51bWJlcjoKZGZzWyw0XSA8LSBhcy5udW1lcmljKGFzLmNoYXJhY3RlcihkZnNbLDRdKSkKCmNvbG5hbWVzKGRmcykgPC0gYygnUHJlZGljdGlvbihTcGVhcm1hbilfS2FzaWEnLCAncihTcGVhcm1hbilfS2FzaWEnLCAnUHJlZGljdGlvbihQZWFyc29uKV9LYXNpYScsICdyKFBlYXJzb24pX0thc2lhJykKI2FkZCB0byBTZXVyYXQ6CiNhZGQgdG8gMTBYIG9iamVjdDoKc3MyX211dGFudHNfZmluYWwgPC0gQWRkTWV0YURhdGEoc3MyX211dGFudHNfZmluYWwsIGRmcykKYGBgCgojIyMgTm9ybWFsaXNhdGlvbgpub3JtYWxpc2UgYW5kIGZpbmQgdmFyaWFibGUgZ2VuZXMKYGBge3J9CiMjIG5vcm1hbGlzZQpzczJfbXV0YW50c19maW5hbCA8LSBOb3JtYWxpemVEYXRhKHNzMl9tdXRhbnRzX2ZpbmFsLCBub3JtYWxpemF0aW9uLm1ldGhvZCA9ICJMb2dOb3JtYWxpemUiLCBzY2FsZS5mYWN0b3IgPSAxMDAwMCkKCiMjIGZpbmQgdmFyaWFibGUgZ2VuZXMKc3MyX211dGFudHNfZmluYWwgPC0gRmluZFZhcmlhYmxlRmVhdHVyZXMoc3MyX211dGFudHNfZmluYWwsIHNlbGVjdGlvbi5tZXRob2QgPSAidnN0IiwgbmZlYXR1cmVzID0gMjAwMCkKCiMjIG1ha2UgYSBsaXN0IG9mIGFsbCBnZW5lcyBpbiB0aGUgZGF0YXNldAphbGwuZ2VuZXMgPC0gcm93bmFtZXMoc3MyX211dGFudHNfZmluYWwpCgojIyBzY2FsZSBkYXRhIG9uIGFsbCBnZW5lcwpzczJfbXV0YW50c19maW5hbCA8LSBTY2FsZURhdGEoc3MyX211dGFudHNfZmluYWwsIGZlYXR1cmVzID0gYWxsLmdlbmVzKQpgYGAKCiMjIyBEaW1lbnNpb25hbGl0eSByZWR1Y3Rpb24KCiMjIyMgUENBCmBgYHtyfQpzczJfbXV0YW50c19maW5hbCA8LSBSdW5QQ0Eoc3MyX211dGFudHNfZmluYWwsIGZlYXR1cmVzID0gVmFyaWFibGVGZWF0dXJlcyhvYmplY3QgPSBzczJfbXV0YW50c19maW5hbCksIHZlcmJvc2UgPSBGQUxTRSkKYGBgCgpQQ0EgcGxvdApgYGB7cn0KRGltUGxvdChzczJfbXV0YW50c19maW5hbCwgcmVkdWN0aW9uID0gInBjYSIsIGdyb3VwLmJ5ID0gInN1Yl9pZGVudGl0eV91cGRhdGVkIikKYGBgCgpgYGB7cn0KRWxib3dQbG90KHNzMl9tdXRhbnRzX2ZpbmFsLCBuZGltcyA9IDMwLCByZWR1Y3Rpb24gPSAicGNhIikKYGBgCgojIyMjIEZpbmQgY2x1c3RlcnMKYGBge3J9CnNzMl9tdXRhbnRzX2ZpbmFsIDwtIEZpbmROZWlnaGJvcnMoc3MyX211dGFudHNfZmluYWwsIGRpbXMgPSAxOjIxKQpzczJfbXV0YW50c19maW5hbCA8LSBGaW5kQ2x1c3RlcnMoc3MyX211dGFudHNfZmluYWwsIHJlc29sdXRpb24gPSAxKQpgYGAKCiMjIyMgVU1BUAoKSW1wcm92ZSBVTUFQCmBgYHtyfQojb2xkIHdheSBvZiBydW5uaW5nIFVNQVA6CiNzczJfbXV0YW50c19maW5hbCA8LVJ1blVNQVAoc3MyX211dGFudHNfZmluYWwsIHJlZHVjdGlvbiA9ICJwY2EiLCBkaW1zID0gMToxMCwgbi5uZWlnaGJvcnMgPSAxNTAsIHNlZWQudXNlID0gMTIzNCwgbWluLmRpc3QgPSAwLjQsIHJlcHVsc2lvbi5zdHJlbmd0aCA9IDAuMDMsIGxvY2FsLmNvbm5lY3Rpdml0eSA9IDE1MCkKc3MyX211dGFudHNfZmluYWwgPC0gUnVuVU1BUChzczJfbXV0YW50c19maW5hbCwgZGltcyA9IDE6MTIpCmBgYAoKYGBge3IsIGZpZy5oZWlnaHQgPSAyLCBmaWcud2lkdGggPSA2fQpwMSA8LSBEaW1QbG90KHNzMl9tdXRhbnRzX2ZpbmFsLCBncm91cC5ieSA9ICJpZGVudCIsIGxhYmVsID0gVFJVRSkKcDIgPC0gRGltUGxvdChzczJfbXV0YW50c19maW5hbCwgZ3JvdXAuYnkgPSAiaWRlbnRpdHlfdXBkYXRlZCIpCnAxICsgcDIKYGBgCgojIyMgQ2x1c3RlciBhc3NpZ25tZW50CgojIyMjIEludGVyYWN0aXZlCmBgYHtyfQpwbG90IDwtIEZlYXR1cmVQbG90KHNzMl9tdXRhbnRzX2ZpbmFsLCBmZWF0dXJlcyA9ICJuRmVhdHVyZV9STkEiKSAgIAoKSG92ZXJMb2NhdG9yKHBsb3QgPSBwbG90LCBpbmZvcm1hdGlvbiA9IEZldGNoRGF0YShzczJfbXV0YW50c19maW5hbCwgdmFycyA9IGMoIm5GZWF0dXJlX1JOQSIsICJpZGVudCIsICJpZGVudGl0eV91cGRhdGVkIikpKQpgYGAKCiMjIyMgbmdlbmVzLCBubWl0bywgbmNvdW50cyB2aXN1YWxpc2F0aW9uCgpgYGB7cn0KIyMgYWRkIGNvbHVtbiB0byBsb2cgY291bnRzIHNvIHRoZXkgYXJlIGVhc2llciB0byB2aXN1YWxpc2UKc3MyX211dGFudHNfZmluYWwgPC0gQWRkTWV0YURhdGEoc3MyX211dGFudHNfZmluYWwsIGxvZzEwKHNzMl9tdXRhbnRzX2ZpbmFsQG1ldGEuZGF0YSRuQ291bnRfUk5BKSwgY29sLm5hbWUgPSAibkNvdW50X2xvZzEwIikKCkZlYXR1cmVQbG90KHNzMl9tdXRhbnRzX2ZpbmFsLCBmZWF0dXJlcyA9IGMoIm5Db3VudF9STkEiLCAibkNvdW50X2xvZzEwIiwgIm5GZWF0dXJlX1JOQSIsICJwZXJjZW50Lm10IikpICAgCmBgYAoKVmlvbGluIHBsb3RzIGNsdXN0ZXItYnktY2x1c3RlcjoKYGBge3J9ClZsblBsb3Qob2JqZWN0ID0gc3MyX211dGFudHNfZmluYWwsIGZlYXR1cmVzID0gIm5GZWF0dXJlX1JOQSIsIHB0LnNpemUgPSAwLjAxKSArCiAgbGFicyh4PSJDbHVzdGVyIiwKICAgICAgIHk9IkdlbmVzIHBlciBDZWxsIiwKICAgICAgIHRpdGxlID0gIk51bWJlciBvZiBHZW5lcyBwZXIgQ2VsbCIpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpCgpWbG5QbG90KG9iamVjdCA9IHNzMl9tdXRhbnRzX2ZpbmFsLCBmZWF0dXJlcyA9ICJuQ291bnRfbG9nMTAiLCBwdC5zaXplID0gMC4wMSkgKwogIGxhYnMoeD0iQ2x1c3RlciIsCiAgICAgICB5PSJMb2cxMChDb3VudHMgcGVyIENlbGwpIiwKICAgICAgIHRpdGxlID0gIk51bWJlciBvZiBDb3VudHMgcGVyIENlbGwiKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQoKVmxuUGxvdChvYmplY3QgPSBzczJfbXV0YW50c19maW5hbCwgZmVhdHVyZXMgPSAicGVyY2VudC5tdCIsIHB0LnNpemUgPSAwLjAxKSArCiAgbGFicyh4PSJDbHVzdGVyIiwKICAgICAgIHk9IiUgTWl0b2Nob25kcmlhbCBSZWFkcyIsCiAgICAgICB0aXRsZSA9ICJQZXJjZW50YWdlIG9mIE1pdG9jaG9uZHJpYWwgUmVhZHMgcGVyIENlbGwiKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQpgYGAKCiMjIyMgRXhwcmVzc2lvbiBvZiBtYXJrZXIgZ2VuZXMKCmBgYHtyLCBmaWcuaGVpZ2h0ID0gNiwgZmlnLndpZHRoID0gOH0KIyBQQkFOS0EtMDUxNTAwMCAtIHAyNSAtIGZlbWFsZQojIFBCQU5LQS0xMzE5NTAwIC0gQ0NQMiAtIGZlbWFsZSAtIHVzZWQgaW4gODIwIGxpbmUKIyBQQkFOS0EtMTIxMjYwMCAtIEhBUDIgLSBtYWxlCiMgUEJBTktBLTA2MDA2MDAgLSBORUszIC0gbWFsZQojIFBCQU5LQS0xMzE1NzAwIC0gUk9OMiAtIChhc2V4dWFscyBhbmQgc29tZSBtYWxlPykKIyAiUEJBTktBLTA0MTYxMDAiIC0gZHluZW5pbiBoZWF2eSBjaGFpbiAtIG1hbGUgLSB1c2VkIGluIDgyMCBsaW5lCiMgUEJBTktBLTE0Mzc1MDAgLSBBUDItRyAtIHNldXhhbCBjb21taXRtZW50IGdlbmUKIyBQQkFOS0EtMDgzMTAwMCAtIE1TUDEgLSBsYXRlIGFzZXh1YWwKIyBQQkFOS0EtMTEwMjIwMCAtIE1TUDggLSBlYXJseSBhc2V4dWFsIChmcm9tIEJvemRlY2ggcGFwZXIpCkZlYXR1cmVQbG90KHNzMl9tdXRhbnRzX2ZpbmFsLCBmZWF0dXJlcyA9IGMoIlBCQU5LQS0wNTE1MDAwIiwgIlBCQU5LQS0xMzE5NTAwIiwgIlBCQU5LQS0xMjEyNjAwIiwiUEJBTktBLTA2MDA2MDAiLCAiUEJBTktBLTEzMTU3MDAiLCAiUEJBTktBLTA0MTYxMDAiLCAiUEJBTktBLTE0Mzc1MDAiLCAiUEJBTktBLTA4MzEwMDAiLCAiUEJBTktBLTExMDIyMDAiKSwgY29vcmQuZml4ZWQgPSBUUlVFKQpgYGAKCiMjIyBEb3RwbG90CgpUaGlzIGVzc2VudGlhbGx5IGFsbG93cyB1cyB0byB2aWV3IHdoaWNoIGdlbm90eXBlcyBzaXQgaW4gd2hpY2ggY2x1c3RlcnMuIFdoZXJlIHdlIHNlZSB0aGF0IFdUIGlzIG5vdCBwcmVzZW50LCB3ZSBjYW4gcHJlc3VtZSB0aGF0IHRoaXMgbXV0YW50IGhhcyBhIHVuaXF1ZSB0cmFuc2NyaXB0b21lIChlaXRoZXIgZnJvbSB0aGUgd2hvbGUgV1QgdHJhamVjdG9yeSBvciBpdCBoYXMgYXJyZXN0ZWQgYW5kIHNvIHJlcHJlc2VudHMgYSBXVCBkZXZlbG9waW5nIGZvcm0gLSB3ZSBjYW4gZmluZCB0aGlzIG91dCBpbiB0aGUgbmV4dCBzdGFnZSBvZiBhbmFsYXlzaXMgd2hlbiB3ZSBpbnRlZ3JhdGUgd2l0aCAxMFggZGF0YSkuCmBgYHtyLCBwcmVwIGZvciBkb3RwbG90fQpkZl9tZXRhX2RhdGEgPC0gYXMuZGF0YS5mcmFtZShzczJfbXV0YW50c19maW5hbEBtZXRhLmRhdGEpCgpkb3RfcGxvdF9kZiA8LSBhcy5kYXRhLmZyYW1lLm1hdHJpeCh0YWJsZShkZl9tZXRhX2RhdGEkUk5BX3Nubl9yZXMuMSwgZGZfbWV0YV9kYXRhJGlkZW50aXR5X3VwZGF0ZWQpKQoKZG90X3Bsb3RfZGZfcGMgPC0gKGFzLmRhdGEuZnJhbWUubWF0cml4KHByb3AudGFibGUodGFibGUoZGZfbWV0YV9kYXRhJFJOQV9zbm5fcmVzLjEsIGRmX21ldGFfZGF0YSRpZGVudGl0eV91cGRhdGVkKSwgbWFyZ2luID0gMikpICogMTAwKQoKZG90X3Bsb3RfZGZfcGMkY2x1c3RlciA8LSByb3duYW1lcyhkb3RfcGxvdF9kZl9wYykKbGlicmFyeShkcGx5cikKZG90X3Bsb3RfZGZfcGNfbXV0YXRlZCA8LSBtdXRhdGUoZG90X3Bsb3RfZGZfcGMpCmxpYnJhcnkocmVzaGFwZTIpCmRvdF9wbG90X2RmX3BjX21lbHRlZCA8LSBtZWx0KGRvdF9wbG90X2RmX3BjLCB2YXJpYWJsZS5uYW1lID0gImNsdXN0ZXIiKQpjb2xuYW1lcyhkb3RfcGxvdF9kZl9wY19tZWx0ZWQpWzJdIDwtICJpZGVudGl0eSIKYGBgCgpgYGB7ciwgZmlnLndpZHRoID0gNCwgZmlnLmhlaWdodD0gNX0KbGlicmFyeShnZ3Bsb3QyKQogIHAgPSBnZ3Bsb3QoZG90X3Bsb3RfZGZfcGNfbWVsdGVkLAogICAgICAgICAgICAgYWVzKHkgPSBmYWN0b3IoY2x1c3RlciksCiAgICAgICAgICAgICAgICAgeCA9IGZhY3RvcihpZGVudGl0eSkpKSArCiAgICAgIGdlb21fcG9pbnQoYWVzKGNvbG91cj12YWx1ZSwgc2l6ZT12YWx1ZSkpICsgCiAgICAgIHNjYWxlX2NvbG9yX2dyYWRpZW50KGxvdz0iYmx1ZSIsIGhpZ2g9InJlZCIsIGxpbWl0cz1jKCAxLCBtYXgoZG90X3Bsb3RfZGZfcGNfbWVsdGVkJHZhbHVlKSksIG5hLnZhbHVlPSJ3aGl0ZSIpICsKICAgICAgdGhlbWVfYncoKSArCiAgICAgIHRoZW1lKHBhbmVsLmdyaWQubWFqb3I9ZWxlbWVudF9ibGFuaygpLCBwYW5lbC5ncmlkLm1pbm9yPWVsZW1lbnRfYmxhbmsoKSkKICBwID0gcCArCiAgICAgIHlsYWIoIkNsdXN0ZXIiKSArCiAgICAgIHhsYWIoIklkZW50aXR5IikgKwogICAgICB0aGVtZShheGlzLnRleHQueD1lbGVtZW50X3RleHQoc2l6ZT0xMiwgZmFjZT0iaXRhbGljIiwgYW5nbGU9NDUsIGhqdXN0PTEpKSArIAogICAgICB0aGVtZShheGlzLnRleHQueT1lbGVtZW50X3RleHQoc2l6ZT0xMiwgZmFjZT0iaXRhbGljIikpCiAgcHJpbnQocCkKYGBgCgpNdXRhbnRzIDMsIDIsIGFuZCAxMyBhbGwgc2VlbSB0byBkaXNwbGF5IHRoaXMgdW5pcXVlIHBoZW5vdHlwZS4gCgojIyMjIGV4cHJlc3Npb24gb2YgODIwIG1hcmtlcnMKCmBgYHtyLCBmaWcuaGVpZ2h0ID0gNCwgZmlnLndpZHRoID0gMTB9CiMjIG1ha2UgcGxvdHMgCnBsb3RzIDwtIEZlYXR1cmVQbG90KHNzMl9tdXRhbnRzX2ZpbmFsLCBmZWF0dXJlcyA9IGMoIlBCQU5LQS0xMzE5NTAwIiwgIlBCQU5LQS0wNDE2MTAwIiksIGJsZW5kID0gVFJVRSwgY29tYmluZSA9IEZBTFNFLCBjb29yZC5maXhlZCA9IFRSVUUpCgojIEdldCBqdXN0IHRoZSBjby1leHByZXNzaW9uIHBsb3QsIGJ1aWx0LWluIGxlZ2VuZCBpcyBtZWFuaW5nbGVzcyBmb3IgdGhpcyBwbG90CiNwbG90c1tbM11dICsgTm9MZWdlbmQoKSAgCgojIEdldCBqdXN0IHRoZSBrZXkKI3Bsb3RzW1s0XV0gCgojIFN0aXRjaCB0aGUgY28tZXhwcmVzc2lvbiBhbmQga2V5IHBsb3RzIHRvZ2V0aGVyCnBsb3RzW1szXV0gKyBOb0xlZ2VuZCgpICsgcGxvdHNbWzRdXS9wbG90X3NwYWNlcigpICsgcGxvdF9sYXlvdXQod2lkdGhzID0gYygyLDEpKQpgYGAKCkNvbmZpcm0gbGlmZSBjeWNsZSBkZXNpZ25hdGlvbnMgdXNpbmcgYnVsayBjb3JyZWxhdGlvbnMKYGBge3J9CkZlYXR1cmVQbG90KHNzMl9tdXRhbnRzX2ZpbmFsLCBmZWF0dXJlcyA9IGMoIlByZWRpY3Rpb24uU3BlYXJtYW4uX0thc2lhIiwgIlByZWRpY3Rpb24uU3BlYXJtYW4uIikpCmBgYAoKIyA0LiBDbHVzdGVyIHRvZ2V0aGVyIHdpdGggTUNBIGRhdGEgey50YWJzZXR9CgojIyBQcmVwYXJlCgojIyMgc2V0IHVwIE1DQSBkYXRhCmBgYHtyfQojIyByZWFkIGluIGRhdGEKY291bnRzX21jYSA8LSByZWFkLnRhYmxlKCIvVXNlcnMvQW5keS9HQ1NLTy9HQ1NLT19hbmFseXNpc19naXQvZGF0YS9SZWZlcmVuY2UvYWxsY291bnRzNC5jc3YiLCBoZWFkZXIgPSBUUlVFLCBzZXAgPSAiLCIsIHJvdy5uYW1lcz0xLCBzdHJpbmdzQXNGYWN0b3JzID0gVFJVRSkKZGltKGNvdW50c19tY2EpCgphbm5vX21jYSA8LSByZWFkLmRlbGltKCIvVXNlcnMvQW5keS9HQ1NLTy9HQ1NLT19hbmFseXNpc19naXQvZGF0YS9SZWZlcmVuY2UvYWxscGhlbm84LjIuY3N2IiwgaGVhZGVyID0gVFJVRSwgc2VwID0gIiwiLCByb3cubmFtZXM9MSkKZGltKGFubm9fbWNhKQoKIyMgc3Vic2V0IGFsbCBibG9vZCBzdGFnZSBjZWxscwojIyBmaW5kIGJsb29kIHN0YWdlcwpibG9vZF9zdGFnZXMgPC0gYygiTWVyb3pvaXRlIiwgIlNoeiIsICJNYWxlIiwgIlNjaGl6b250IiwgIkZlbWFsZSIsICJUcm9waG96b2l0ZSIsICJSaW5nIikKCmJsb29kX3N0YWdlX2NlbGxfbmFtZXMgPC0gcm93bmFtZXMoYW5ub19tY2FbYW5ub19tY2EkU2hvcnRlbmVkTGlmZVN0YWdlMiAlaW4lIGJsb29kX3N0YWdlcywgXSkKCiMjIHN1YnNldCBkYXRhZnJhbWVzCmNvdW50c19tY2FfYmxvb2Rfc3RhZ2UgPC0gY291bnRzX21jYVsgLGNvbG5hbWVzKGNvdW50c19tY2EpICVpbiUgYmxvb2Rfc3RhZ2VfY2VsbF9uYW1lc10KZGltKGNvdW50c19tY2FfYmxvb2Rfc3RhZ2UpCgphbm5vX21jYV9ibG9vZF9zdGFnZSA8LSBhbm5vX21jYVtyb3duYW1lcyhhbm5vX21jYSkgJWluJSBibG9vZF9zdGFnZV9jZWxsX25hbWVzLCBdCmRpbShhbm5vX21jYV9ibG9vZF9zdGFnZSkKCiMjIHJlbW92ZSBjb250cm9sIGNlbGxzOgpub25fY29udHJvbF9jZWxsX25hbWVzIDwtIHJvd25hbWVzKGFubm9fbWNhX2Jsb29kX3N0YWdlW2Fubm9fbWNhX2Jsb29kX3N0YWdlJE51bWJlcl9vZl9jZWxscyA9PSAxLCBdKQpjb3VudHNfbWNhX2Jsb29kX3N0YWdlIDwtIGNvdW50c19tY2FfYmxvb2Rfc3RhZ2VbICxjb2xuYW1lcyhjb3VudHNfbWNhX2Jsb29kX3N0YWdlKSAlaW4lIG5vbl9jb250cm9sX2NlbGxfbmFtZXNdCmRpbShjb3VudHNfbWNhX2Jsb29kX3N0YWdlKQoKYW5ub19tY2FfYmxvb2Rfc3RhZ2UgPC0gYW5ub19tY2FfYmxvb2Rfc3RhZ2Vbcm93bmFtZXMoYW5ub19tY2FfYmxvb2Rfc3RhZ2UpICVpbiUgbm9uX2NvbnRyb2xfY2VsbF9uYW1lcywgXQpkaW0oYW5ub19tY2FfYmxvb2Rfc3RhZ2UpCgojIyBjaGVjawppZGVudGljYWwocm93bmFtZXMoY291bnRzX21jYV9ibG9vZF9zdGFnZSksIHJvd25hbWVzKGNvdW50cykpCmBgYAoKIyMjIHNldCB1cCBNQ0Egb2JqZWN0CgptY2Egb2JqZWN0CmBgYHtyfQojIyBtYWtlIFNldXJhdCBvYmplY3Qgd2l0aCBzYW1lIGZpbHRlcmluZyBhcyBtYWluIG9iamVjdCBiZWNhdXNlIHRoZXkgYXJlIHNlcXVlbmNlZCB0byBzYW1lIGRlcHRoOgpHQ1NLT19tY2EgPC0gQ3JlYXRlU2V1cmF0T2JqZWN0KGNvdW50cyA9IGNvdW50c19tY2FfYmxvb2Rfc3RhZ2UsIG1ldGEuZGF0YSA9IGFubm9fbWNhX2Jsb29kX3N0YWdlLCBtaW4uY2VsbHMgPSAwLCBtaW4uZmVhdHVyZXMgPSAxMjAsIHByb2plY3QgPSAiR0NTS08iKQoKR0NTS09fbWNhCgpHQ1NLT19tY2FAbWV0YS5kYXRhJGV4cGVyaW1lbnQgPC0gIm1jYSIKc3MyX211dGFudHNfZmluYWxAbWV0YS5kYXRhJGV4cGVyaW1lbnQgPC0gInNzMl9tdXRhbnRzIgpgYGAKbi5iLiBhIGZpbHRlciBvZiA0MCBhbGxvd3MgdGhlIG1lcm96b2l0ZXMgdG8gY29tcGxldGUgdGhlIHJpbmcgaW4gdGhlIGFzZXh1YWxzCgpgYGB7cn0KVmxuUGxvdChvYmplY3QgPSBHQ1NLT19tY2EsIGZlYXR1cmVzID0gIm5GZWF0dXJlX1JOQSIsIHB0LnNpemUgPSAwLjAxKSArCiAgbGFicyh4PSJDbHVzdGVyIiwKICAgICAgIHk9IkdlbmVzIHBlciBDZWxsIiwKICAgICAgIHRpdGxlID0gIk51bWJlciBvZiBHZW5lcyBwZXIgQ2VsbCIpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpICsgZ2VvbV9obGluZSh5aW50ZXJjZXB0PTIyMCkKClZsblBsb3Qob2JqZWN0ID0gR0NTS09fbWNhLCBmZWF0dXJlcyA9ICJuQ291bnRfUk5BIiwgcHQuc2l6ZSA9IDAuMDEpICsKICBsYWJzKHg9IkNsdXN0ZXIiLAogICAgICAgeT0iTG9nMTAoQ291bnRzIHBlciBDZWxsKSIsCiAgICAgICB0aXRsZSA9ICJOdW1iZXIgb2YgQ291bnRzIHBlciBDZWxsIikgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikKYGBgCgojIyMgbm9ybWFsaXNlIG9iamVjdApgYGB7cn0KIyMgbm9ybWFsaXNlCkdDU0tPX21jYSA8LSBOb3JtYWxpemVEYXRhKEdDU0tPX21jYSwgbm9ybWFsaXphdGlvbi5tZXRob2QgPSAiTG9nTm9ybWFsaXplIiwgc2NhbGUuZmFjdG9yID0gMTAwMDApCiMjIGZpbmQgdmFyaWFibGUgZ2VuZXMKR0NTS09fbWNhIDwtIEZpbmRWYXJpYWJsZUZlYXR1cmVzKEdDU0tPX21jYSwgc2VsZWN0aW9uLm1ldGhvZCA9ICJ2c3QiLCBuZmVhdHVyZXMgPSAyMDAwKQojIyBtYWtlIGEgbGlzdCBvZiBhbGwgZ2VuZXMgaW4gdGhlIGRhdGFzZXQKYWxsLmdlbmVzIDwtIHJvd25hbWVzKEdDU0tPX21jYSkKIyMgc2NhbGUgZGF0YSBvbiBhbGwgZ2VuZXMKR0NTS09fbWNhIDwtIFNjYWxlRGF0YShHQ1NLT19tY2EsIGZlYXR1cmVzID0gYWxsLmdlbmVzKQpgYGAKCiMjIyBJbnRlZ3JhdGUKCmBgYHtyfQojIyBtYWtlIGxpc3QKc3MyLm1jYS5saXN0IDwtIGxpc3QoR0NTS09fbWNhLCBzczJfbXV0YW50c19maW5hbCkKc3MyLm1jYS5hbmNob3JzIDwtIEZpbmRJbnRlZ3JhdGlvbkFuY2hvcnMob2JqZWN0Lmxpc3QgPSBzczIubWNhLmxpc3QsIGRpbXMgPSAxOjIxLCB2ZXJib3NlID0gRkFMU0UpCnNzMi5tY2EuaW50ZWdyYXRlZCA8LSBJbnRlZ3JhdGVEYXRhKGFuY2hvcnNldCA9IHNzMi5tY2EuYW5jaG9ycywgZGltcyA9IDE6MjEsIHZlcmJvc2UgPSBGQUxTRSwgZmVhdHVyZXMudG8uaW50ZWdyYXRlID0gYWxsLmdlbmVzKQpgYGAKCiMjIyBBbmFseXNlCgpTY2FsZSBhbmQgUENBCmBgYHtyfQojIHNldCBkdXJpbmcgSW50ZWdyYXRlRGF0YQpEZWZhdWx0QXNzYXkoc3MyLm1jYS5pbnRlZ3JhdGVkKSA8LSAiaW50ZWdyYXRlZCIKIyBSdW4gdGhlIHN0YW5kYXJkIHdvcmtmbG93IGZvciB2aXN1YWxpemF0aW9uIGFuZCBjbHVzdGVyaW5nCnNzMi5tY2EuaW50ZWdyYXRlZCA8LSBTY2FsZURhdGEoc3MyLm1jYS5pbnRlZ3JhdGVkLCB2ZXJib3NlID0gRkFMU0UpCnNzMi5tY2EuaW50ZWdyYXRlZCA8LSBSdW5QQ0Eoc3MyLm1jYS5pbnRlZ3JhdGVkLCBucGNzID0gMzAsIHZlcmJvc2UgPSBGQUxTRSkKYGBgCgpJbnNwZWN0IFBDUzoKYGBge3J9CkVsYm93UGxvdChzczIubWNhLmludGVncmF0ZWQsIG5kaW1zID0gMzAsIHJlZHVjdGlvbiA9ICJwY2EiKQpgYGAKClVNQVAKYGBge3IgVU1BUCBydW59CiMjIHJ1biBVTUFQCnNzMi5tY2EuaW50ZWdyYXRlZCA8LSBSdW5VTUFQKHNzMi5tY2EuaW50ZWdyYXRlZCwgcmVkdWN0aW9uID0gInBjYSIsIGRpbXMgPSAxOjE1KQpgYGAKCmBgYHtyIFVNQVAgcGxvdH0KIyMgYWRkIG5ldyBjb2x1bW4gCnNzMi5tY2EuaW50ZWdyYXRlZEBtZXRhLmRhdGEkY2x1c3RlcnNfaW50ZWdyYXRlZCA8LSBzczIubWNhLmludGVncmF0ZWRAbWV0YS5kYXRhJHNldXJhdF9jbHVzdGVycwoKc3MyLm1jYS5pbnRlZ3JhdGVkQG1ldGEuZGF0YSRjbHVzdGVyc19pbnRlZ3JhdGVkIDwtIGlmZWxzZShpcy5uYShzczIubWNhLmludGVncmF0ZWRAbWV0YS5kYXRhJGNsdXN0ZXJzX2ludGVncmF0ZWQpLCBzczIubWNhLmludGVncmF0ZWRAbWV0YS5kYXRhJFNob3J0ZW5lZExpZmVTdGFnZTIsIHNzMi5tY2EuaW50ZWdyYXRlZEBtZXRhLmRhdGEkY2x1c3RlcnNfaW50ZWdyYXRlZCkKCkRpbVBsb3Qoc3MyLm1jYS5pbnRlZ3JhdGVkLCBwdC5zaXplID0gMC4wMSwgbGFiZWwgPSBUUlVFLCBzcGxpdC5ieSA9ICJleHBlcmltZW50IiwgZ3JvdXAuYnkgPSAiY2x1c3RlcnNfaW50ZWdyYXRlZCIpICsgY29vcmRfZml4ZWQoKSArIHRoZW1lX3ZvaWQoKQpgYGAKCmBgYHtyfQpWbG5QbG90KG9iamVjdCA9IHNzMi5tY2EuaW50ZWdyYXRlZCwgZmVhdHVyZXMgPSAibkZlYXR1cmVfUk5BIiwgcHQuc2l6ZSA9IDAuMDEpICsgZ2VvbV9obGluZSh5aW50ZXJjZXB0PTEwMCkKYGBgCgojIyMgY2x1c3RlcgoKZ2VuZXJhdGUgY2x1c3RlcnM6CmBgYHtyfQojIyBjb3B5IG9sZCBjbHVzdGVycwojc3MyLm1jYS5pbnRlZ3JhdGVkIDwtIEFkZE1ldGFEYXRhKHNzMi5tY2EuaW50ZWdyYXRlZCwgc3MyLm1jYS5pbnRlZ3JhdGVkQG1ldGEuZGF0YSRSTkFfc25uX3Jlcy4xLCBjb2wubmFtZSA9ICJwcmVfaW50ZWdyYXRpb25fY2x1c3RlcnMiKQoKIyMgZ2VuZXJhdGUgbmV3IGNsdXN0ZXJzCiNzczIubWNhLmludGVncmF0ZWQgPC0gRmluZE5laWdoYm9ycyhzczIubWNhLmludGVncmF0ZWQsIGRpbXMgPSAxOjIxKQojc3MyLm1jYS5pbnRlZ3JhdGVkIDwtIEZpbmRDbHVzdGVycyhzczIubWNhLmludGVncmF0ZWQsIHJlc29sdXRpb24gPSAxLCByYW5kb20uc2VlZCA9IDQyLCBhbGdvcml0aG0gPSAyKQpgYGAKCiMgU2F2ZSB7LnRhYnNldH0KCnNhdmUgY291bnRzIGFuZCBwaGVubyB3aXRob3V0IGFub3BoZWxlcyBhbmQgY29udHJvbCBjZWxscwpgYGB7cn0Kd3JpdGUuY3N2KGNvdW50cywgZmlsZSA9ICIvVXNlcnMvQW5keS9HQ1NLTy9HQ1NLT19hbmFseXNpc19naXQvZGF0YV90b19leHBvcnQvY291bnRzXzIwMjBfZmlsdGVyZWQuY3N2IikKd3JpdGUuY3N2KHBoZW5vLCBmaWxlID0gIi9Vc2Vycy9BbmR5L0dDU0tPL0dDU0tPX2FuYWx5c2lzX2dpdC9kYXRhX3RvX2V4cG9ydC9waGVub18yMDIwX2ZpbHRlcmVkLmNzdiIpCmBgYAoKc2F2ZSBjb3VudHMgYW5kIHBoZW5vIG9iamVjdHMKYGBge3J9CnBoZW5vX2ZpbHRlcmVkX2NlbGxzIDwtIHNzMl9tdXRhbnRzX2ZpbmFsQG1ldGEuZGF0YQpjb3VudHNfZmlsdGVyZWRfY2VsbHMgPC0gc3MyX211dGFudHNfZmluYWxAYXNzYXlzJFJOQUBjb3VudHMKCndyaXRlLmNzdihjb3VudHNfZmlsdGVyZWRfY2VsbHMsIGZpbGUgPSAiL1VzZXJzL0FuZHkvR0NTS08vR0NTS09fYW5hbHlzaXNfZ2l0L2RhdGFfdG9fZXhwb3J0L2NvdW50c19wb3N0X3FjLmNzdiIpCndyaXRlLmNzdihwaGVub19maWx0ZXJlZF9jZWxscywgZmlsZSA9ICIvVXNlcnMvQW5keS9HQ1NLTy9HQ1NLT19hbmFseXNpc19naXQvZGF0YV90b19leHBvcnQvcGhlbm9fcG9zdF9xYy5jc3YiKQpgYGAKCnNhdmUgdGhlIHNlc3Npb24gb2JqZWN0cwpgYGB7cn0KIyMgc2F2ZSBhbGwgZGF0YSAKI3NhdmUuaW1hZ2UoZmlsZSA9ICIvVXNlcnMvQW5keS9HQ1NLTy9HQ1NLT19hbmFseXNpc19naXQvR0NTS09fU1MyX1FDLlJEYXRhIikKI2xvYWQoZmlsZSA9ICIvVXNlcnMvQW5keS9HQ1NLTy9HQ1NLT19hbmFseXNpc19naXQvR0NTS09fU1MyX1FDLlJEYXRhIikKCiMjIHNhdmUgZmluYWwgb2JqZWN0CnNhdmVSRFMoc3MyX211dGFudHNfZmluYWwsIGZpbGUgPSAiL1VzZXJzL0FuZHkvR0NTS08vR0NTS09fYW5hbHlzaXNfZ2l0L2RhdGFfdG9fZXhwb3J0L3NzMl9tdXRhbnRzX2ZpbmFsLlJEUyIpIAojIyB0byByZWFkIHRoaXMgb2JqZWN0IGJhY2sgaW4gaWYgbmVlZGVkCiNzczJfbXV0YW50c19maW5hbCA8LSByZWFkUkRTKCIvVXNlcnMvQW5keS9HQ1NLTy9HQ1NLT19hbmFseXNpc19naXQvc3MyX211dGFudHNfZmluYWwuUkRTIikKYGBgCgojIEFwcGVuZGl4IHsudGFic2V0fQoKIyMgU2Vzc2lvbiBJbmZvIApgYGB7ciwgZWNobyA9IEZBTFNFfQpzZXNzaW9uSW5mbygpCmBgYAo=